From 9cf1dd71d7301e9e3ee57f5edaafc698560cb225 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Wed, 21 Feb 2024 14:45:07 +0100 Subject: [PATCH] Build Filament Headers --- package/android/libs/filament/LICENSE | 202 +++ package/android/libs/filament/README.md | 182 +++ .../filament/include/backend/AcquiredImage.h | 39 + .../include/backend/BufferDescriptor.h | 222 +++ .../include/backend/CallbackHandler.h | 72 + .../include/backend/DriverApiForward.h | 28 + .../filament/include/backend/DriverEnums.h | 1269 +++++++++++++++++ .../libs/filament/include/backend/Handle.h | 132 ++ .../filament/include/backend/PipelineState.h | 45 + .../include/backend/PixelBufferDescriptor.h | 318 +++++ .../libs/filament/include/backend/Platform.h | 198 +++ .../include/backend/PresentCallable.h | 102 ++ .../libs/filament/include/backend/Program.h | 165 +++ .../libs/filament/include/backend/README.md | 4 + .../include/backend/SamplerDescriptor.h | 36 + .../include/backend/TargetBufferInfo.h | 94 ++ .../backend/platforms/OpenGLPlatform.h | 312 ++++ .../backend/platforms/PlatformCocoaGL.h | 73 + .../backend/platforms/PlatformCocoaTouchGL.h | 72 + .../include/backend/platforms/PlatformEGL.h | 162 +++ .../backend/platforms/PlatformEGLAndroid.h | 88 ++ .../backend/platforms/PlatformEGLHeadless.h | 40 + .../include/backend/platforms/PlatformGLX.h | 67 + .../include/backend/platforms/PlatformWGL.h | 70 + .../include/backend/platforms/PlatformWebGL.h | 55 + .../backend/platforms/VulkanPlatform.h | 252 ++++ .../libs/filament/include/camutils/Bookmark.h | 85 ++ .../filament/include/camutils/Manipulator.h | 298 ++++ .../libs/filament/include/camutils/compiler.h | 26 + .../libs/filament/include/filamat/Enums.h | 98 ++ .../include/filamat/IncludeCallback.h | 71 + .../include/filamat/MaterialBuilder.h | 888 ++++++++++++ .../libs/filament/include/filamat/Package.h | 103 ++ .../IBLPrefilterContext.h | 339 +++++ .../libs/filament/include/filament/Box.h | 248 ++++ .../filament/include/filament/BufferObject.h | 122 ++ .../libs/filament/include/filament/Camera.h | 584 ++++++++ .../libs/filament/include/filament/Color.h | 217 +++ .../filament/include/filament/ColorGrading.h | 491 +++++++ .../filament/include/filament/ColorSpace.h | 255 ++++ .../filament/include/filament/DebugRegistry.h | 141 ++ .../libs/filament/include/filament/Engine.h | 936 ++++++++++++ .../libs/filament/include/filament/Exposure.h | 129 ++ .../libs/filament/include/filament/Fence.h | 88 ++ .../filament/include/filament/FilamentAPI.h | 59 + .../libs/filament/include/filament/Frustum.h | 130 ++ .../filament/include/filament/IndexBuffer.h | 129 ++ .../filament/include/filament/IndirectLight.h | 356 +++++ .../include/filament/InstanceBuffer.h | 106 ++ .../filament/include/filament/LightManager.h | 977 +++++++++++++ .../libs/filament/include/filament/Material.h | 394 +++++ .../include/filament/MaterialChunkType.h | 99 ++ .../filament/include/filament/MaterialEnums.h | 255 ++++ .../include/filament/MaterialInstance.h | 501 +++++++ .../include/filament/MorphTargetBuffer.h | 149 ++ .../libs/filament/include/filament/Options.h | 607 ++++++++ .../filament/include/filament/RenderTarget.h | 193 +++ .../include/filament/RenderableManager.h | 921 ++++++++++++ .../libs/filament/include/filament/Renderer.h | 587 ++++++++ .../libs/filament/include/filament/Scene.h | 187 +++ .../include/filament/SkinningBuffer.h | 125 ++ .../libs/filament/include/filament/Skybox.h | 186 +++ .../libs/filament/include/filament/Stream.h | 221 +++ .../filament/include/filament/SwapChain.h | 305 ++++ .../libs/filament/include/filament/Texture.h | 556 ++++++++ .../include/filament/TextureSampler.h | 209 +++ .../filament/include/filament/ToneMapper.h | 253 ++++ .../include/filament/TransformManager.h | 344 +++++ .../filament/include/filament/VertexBuffer.h | 221 +++ .../libs/filament/include/filament/View.h | 910 ++++++++++++ .../libs/filament/include/filament/Viewport.h | 88 ++ .../filament/include/filameshio/MeshReader.h | 120 ++ .../include/geometry/SurfaceOrientation.h | 131 ++ .../include/geometry/TangentSpaceMesh.h | 392 +++++ .../filament/include/geometry/Transcoder.h | 105 ++ .../libs/filament/include/gltfio/Animator.h | 120 ++ .../filament/include/gltfio/AssetLoader.h | 249 ++++ .../filament/include/gltfio/FilamentAsset.h | 303 ++++ .../include/gltfio/FilamentInstance.h | 174 +++ .../include/gltfio/MaterialProvider.h | 214 +++ .../filament/include/gltfio/NodeManager.h | 110 ++ .../filament/include/gltfio/ResourceLoader.h | 167 +++ .../filament/include/gltfio/TextureProvider.h | 187 +++ .../include/gltfio/TrsTransformManager.h | 114 ++ .../include/gltfio/materials/uberarchive.h | 13 + .../libs/filament/include/gltfio/math.h | 128 ++ .../libs/filament/include/ibl/Cubemap.h | 199 +++ .../libs/filament/include/ibl/CubemapIBL.h | 91 ++ .../libs/filament/include/ibl/CubemapSH.h | 125 ++ .../libs/filament/include/ibl/CubemapUtils.h | 124 ++ .../android/libs/filament/include/ibl/Image.h | 77 + .../libs/filament/include/ibl/utilities.h | 57 + .../filament/include/image/ColorTransform.h | 381 +++++ .../libs/filament/include/image/ImageOps.h | 91 ++ .../filament/include/image/ImageSampler.h | 164 +++ .../libs/filament/include/image/Ktx1Bundle.h | 289 ++++ .../libs/filament/include/image/LinearImage.h | 121 ++ .../filament/include/ktxreader/Ktx1Reader.h | 149 ++ .../filament/include/ktxreader/Ktx2Reader.h | 203 +++ .../libs/filament/include/math/TMatHelpers.h | 807 +++++++++++ .../libs/filament/include/math/TQuatHelpers.h | 294 ++++ .../libs/filament/include/math/TVecHelpers.h | 654 +++++++++ .../libs/filament/include/math/compiler.h | 127 ++ .../android/libs/filament/include/math/fast.h | 175 +++ .../android/libs/filament/include/math/half.h | 224 +++ .../android/libs/filament/include/math/mat2.h | 347 +++++ .../android/libs/filament/include/math/mat3.h | 540 +++++++ .../android/libs/filament/include/math/mat4.h | 667 +++++++++ .../libs/filament/include/math/mathfwd.h | 97 ++ .../android/libs/filament/include/math/norm.h | 100 ++ .../android/libs/filament/include/math/quat.h | 202 +++ .../libs/filament/include/math/scalar.h | 124 ++ .../android/libs/filament/include/math/vec2.h | 114 ++ .../android/libs/filament/include/math/vec3.h | 133 ++ .../android/libs/filament/include/math/vec4.h | 133 ++ .../libs/filament/include/mathio/ostream.h | 58 + .../filament/include/mikktspace/mikktspace.h | 145 ++ .../include/tsl/robin_growth_policy.h | 290 ++++ .../libs/filament/include/tsl/robin_hash.h | 1252 ++++++++++++++++ .../libs/filament/include/tsl/robin_map.h | 668 +++++++++ .../libs/filament/include/tsl/robin_set.h | 535 +++++++ .../filament/include/uberz/ArchiveEnums.h | 32 + .../filament/include/uberz/ReadableArchive.h | 79 + .../filament/include/uberz/WritableArchive.h | 67 + .../libs/filament/include/utils/Allocator.h | 924 ++++++++++++ .../libs/filament/include/utils/BitmaskEnum.h | 141 ++ .../libs/filament/include/utils/CString.h | 252 ++++ .../libs/filament/include/utils/CallStack.h | 128 ++ .../libs/filament/include/utils/Entity.h | 88 ++ .../filament/include/utils/EntityInstance.h | 88 ++ .../filament/include/utils/EntityManager.h | 137 ++ .../include/utils/FixedCapacityVector.h | 422 ++++++ .../libs/filament/include/utils/Invocable.h | 152 ++ .../android/libs/filament/include/utils/Log.h | 46 + .../libs/filament/include/utils/Mutex.h | 26 + .../include/utils/NameComponentManager.h | 108 ++ .../libs/filament/include/utils/Panic.h | 563 ++++++++ .../libs/filament/include/utils/Path.h | 303 ++++ .../utils/PrivateImplementation-impl.h | 66 + .../include/utils/PrivateImplementation.h | 59 + .../utils/SingleInstanceComponentManager.h | 316 ++++ .../libs/filament/include/utils/Slice.h | 148 ++ .../include/utils/StructureOfArrays.h | 715 ++++++++++ .../libs/filament/include/utils/algorithm.h | 226 +++ .../libs/filament/include/utils/bitset.h | 330 +++++ .../libs/filament/include/utils/compiler.h | 271 ++++ .../filament/include/utils/compressed_pair.h | 68 + .../libs/filament/include/utils/debug.h | 33 + .../libs/filament/include/utils/linux/Mutex.h | 66 + .../libs/filament/include/utils/memalign.h | 113 ++ .../libs/filament/include/utils/ostream.h | 146 ++ .../libs/filament/include/utils/unwindows.h | 51 + .../include/viewer/AutomationEngine.h | 264 ++++ .../filament/include/viewer/AutomationSpec.h | 86 ++ .../filament/include/viewer/RemoteServer.h | 102 ++ .../libs/filament/include/viewer/Settings.h | 258 ++++ .../libs/filament/include/viewer/ViewerGui.h | 291 ++++ package/ios/libs/filament/LICENSE | 202 +++ package/ios/libs/filament/README.md | 182 +++ .../filament/include/backend/AcquiredImage.h | 39 + .../include/backend/BufferDescriptor.h | 222 +++ .../include/backend/CallbackHandler.h | 72 + .../include/backend/DriverApiForward.h | 28 + .../filament/include/backend/DriverEnums.h | 1269 +++++++++++++++++ .../libs/filament/include/backend/Handle.h | 132 ++ .../filament/include/backend/PipelineState.h | 45 + .../include/backend/PixelBufferDescriptor.h | 318 +++++ .../libs/filament/include/backend/Platform.h | 198 +++ .../include/backend/PresentCallable.h | 102 ++ .../libs/filament/include/backend/Program.h | 165 +++ .../libs/filament/include/backend/README.md | 4 + .../include/backend/SamplerDescriptor.h | 36 + .../include/backend/TargetBufferInfo.h | 94 ++ .../backend/platforms/OpenGLPlatform.h | 312 ++++ .../backend/platforms/PlatformCocoaGL.h | 73 + .../backend/platforms/PlatformCocoaTouchGL.h | 72 + .../include/backend/platforms/PlatformEGL.h | 162 +++ .../backend/platforms/PlatformEGLAndroid.h | 88 ++ .../backend/platforms/PlatformEGLHeadless.h | 40 + .../include/backend/platforms/PlatformGLX.h | 67 + .../include/backend/platforms/PlatformWGL.h | 70 + .../include/backend/platforms/PlatformWebGL.h | 55 + .../backend/platforms/VulkanPlatform.h | 252 ++++ .../libs/filament/include/camutils/Bookmark.h | 85 ++ .../filament/include/camutils/Manipulator.h | 298 ++++ .../libs/filament/include/camutils/compiler.h | 26 + .../ios/libs/filament/include/filamat/Enums.h | 98 ++ .../include/filamat/IncludeCallback.h | 71 + .../include/filamat/MaterialBuilder.h | 888 ++++++++++++ .../libs/filament/include/filamat/Package.h | 103 ++ .../IBLPrefilterContext.h | 339 +++++ .../ios/libs/filament/include/filament/Box.h | 248 ++++ .../filament/include/filament/BufferObject.h | 122 ++ .../libs/filament/include/filament/Camera.h | 584 ++++++++ .../libs/filament/include/filament/Color.h | 217 +++ .../filament/include/filament/ColorGrading.h | 491 +++++++ .../filament/include/filament/ColorSpace.h | 255 ++++ .../filament/include/filament/DebugRegistry.h | 141 ++ .../libs/filament/include/filament/Engine.h | 936 ++++++++++++ .../libs/filament/include/filament/Exposure.h | 129 ++ .../libs/filament/include/filament/Fence.h | 88 ++ .../filament/include/filament/FilamentAPI.h | 59 + .../libs/filament/include/filament/Frustum.h | 130 ++ .../filament/include/filament/IndexBuffer.h | 129 ++ .../filament/include/filament/IndirectLight.h | 356 +++++ .../include/filament/InstanceBuffer.h | 106 ++ .../filament/include/filament/LightManager.h | 977 +++++++++++++ .../libs/filament/include/filament/Material.h | 394 +++++ .../include/filament/MaterialChunkType.h | 99 ++ .../filament/include/filament/MaterialEnums.h | 255 ++++ .../include/filament/MaterialInstance.h | 501 +++++++ .../include/filament/MorphTargetBuffer.h | 149 ++ .../libs/filament/include/filament/Options.h | 607 ++++++++ .../filament/include/filament/RenderTarget.h | 193 +++ .../include/filament/RenderableManager.h | 921 ++++++++++++ .../libs/filament/include/filament/Renderer.h | 587 ++++++++ .../libs/filament/include/filament/Scene.h | 187 +++ .../include/filament/SkinningBuffer.h | 125 ++ .../libs/filament/include/filament/Skybox.h | 186 +++ .../libs/filament/include/filament/Stream.h | 221 +++ .../filament/include/filament/SwapChain.h | 305 ++++ .../libs/filament/include/filament/Texture.h | 556 ++++++++ .../include/filament/TextureSampler.h | 209 +++ .../filament/include/filament/ToneMapper.h | 253 ++++ .../include/filament/TransformManager.h | 344 +++++ .../filament/include/filament/VertexBuffer.h | 221 +++ .../ios/libs/filament/include/filament/View.h | 910 ++++++++++++ .../libs/filament/include/filament/Viewport.h | 88 ++ .../filament/include/filameshio/MeshReader.h | 120 ++ .../include/geometry/SurfaceOrientation.h | 131 ++ .../include/geometry/TangentSpaceMesh.h | 392 +++++ .../filament/include/geometry/Transcoder.h | 105 ++ .../libs/filament/include/gltfio/Animator.h | 120 ++ .../filament/include/gltfio/AssetLoader.h | 249 ++++ .../filament/include/gltfio/FilamentAsset.h | 303 ++++ .../include/gltfio/FilamentInstance.h | 174 +++ .../include/gltfio/MaterialProvider.h | 214 +++ .../filament/include/gltfio/NodeManager.h | 110 ++ .../filament/include/gltfio/ResourceLoader.h | 167 +++ .../filament/include/gltfio/TextureProvider.h | 187 +++ .../include/gltfio/TrsTransformManager.h | 114 ++ .../include/gltfio/materials/uberarchive.h | 13 + .../ios/libs/filament/include/gltfio/math.h | 128 ++ .../ios/libs/filament/include/ibl/Cubemap.h | 199 +++ .../libs/filament/include/ibl/CubemapIBL.h | 91 ++ .../ios/libs/filament/include/ibl/CubemapSH.h | 125 ++ .../libs/filament/include/ibl/CubemapUtils.h | 124 ++ package/ios/libs/filament/include/ibl/Image.h | 77 + .../ios/libs/filament/include/ibl/utilities.h | 57 + .../filament/include/image/ColorTransform.h | 381 +++++ .../libs/filament/include/image/ImageOps.h | 91 ++ .../filament/include/image/ImageSampler.h | 164 +++ .../libs/filament/include/image/Ktx1Bundle.h | 289 ++++ .../libs/filament/include/image/LinearImage.h | 121 ++ .../filament/include/ktxreader/Ktx1Reader.h | 149 ++ .../filament/include/ktxreader/Ktx2Reader.h | 203 +++ .../libs/filament/include/math/TMatHelpers.h | 807 +++++++++++ .../libs/filament/include/math/TQuatHelpers.h | 294 ++++ .../libs/filament/include/math/TVecHelpers.h | 654 +++++++++ .../ios/libs/filament/include/math/compiler.h | 127 ++ package/ios/libs/filament/include/math/fast.h | 175 +++ package/ios/libs/filament/include/math/half.h | 224 +++ package/ios/libs/filament/include/math/mat2.h | 347 +++++ package/ios/libs/filament/include/math/mat3.h | 540 +++++++ package/ios/libs/filament/include/math/mat4.h | 667 +++++++++ .../ios/libs/filament/include/math/mathfwd.h | 97 ++ package/ios/libs/filament/include/math/norm.h | 100 ++ package/ios/libs/filament/include/math/quat.h | 202 +++ .../ios/libs/filament/include/math/scalar.h | 124 ++ package/ios/libs/filament/include/math/vec2.h | 114 ++ package/ios/libs/filament/include/math/vec3.h | 133 ++ package/ios/libs/filament/include/math/vec4.h | 133 ++ .../libs/filament/include/mathio/ostream.h | 58 + .../filament/include/mikktspace/mikktspace.h | 145 ++ .../include/tsl/robin_growth_policy.h | 290 ++++ .../libs/filament/include/tsl/robin_hash.h | 1252 ++++++++++++++++ .../ios/libs/filament/include/tsl/robin_map.h | 668 +++++++++ .../ios/libs/filament/include/tsl/robin_set.h | 535 +++++++ .../filament/include/uberz/ArchiveEnums.h | 32 + .../filament/include/uberz/ReadableArchive.h | 79 + .../filament/include/uberz/WritableArchive.h | 67 + .../libs/filament/include/utils/Allocator.h | 924 ++++++++++++ .../libs/filament/include/utils/BitmaskEnum.h | 141 ++ .../ios/libs/filament/include/utils/CString.h | 252 ++++ .../libs/filament/include/utils/CallStack.h | 128 ++ .../ios/libs/filament/include/utils/Entity.h | 88 ++ .../filament/include/utils/EntityInstance.h | 88 ++ .../filament/include/utils/EntityManager.h | 137 ++ .../include/utils/FixedCapacityVector.h | 422 ++++++ .../libs/filament/include/utils/Invocable.h | 152 ++ package/ios/libs/filament/include/utils/Log.h | 46 + .../ios/libs/filament/include/utils/Mutex.h | 26 + .../include/utils/NameComponentManager.h | 108 ++ .../ios/libs/filament/include/utils/Panic.h | 563 ++++++++ .../ios/libs/filament/include/utils/Path.h | 303 ++++ .../utils/PrivateImplementation-impl.h | 66 + .../include/utils/PrivateImplementation.h | 59 + .../utils/SingleInstanceComponentManager.h | 316 ++++ .../ios/libs/filament/include/utils/Slice.h | 148 ++ .../include/utils/StructureOfArrays.h | 715 ++++++++++ .../libs/filament/include/utils/algorithm.h | 226 +++ .../ios/libs/filament/include/utils/bitset.h | 330 +++++ .../libs/filament/include/utils/compiler.h | 271 ++++ .../filament/include/utils/compressed_pair.h | 68 + .../ios/libs/filament/include/utils/debug.h | 33 + .../filament/include/utils/generic/Mutex.h | 28 + .../libs/filament/include/utils/memalign.h | 113 ++ .../ios/libs/filament/include/utils/ostream.h | 146 ++ .../libs/filament/include/utils/unwindows.h | 51 + .../include/viewer/AutomationEngine.h | 264 ++++ .../filament/include/viewer/AutomationSpec.h | 86 ++ .../filament/include/viewer/RemoteServer.h | 102 ++ .../libs/filament/include/viewer/Settings.h | 258 ++++ .../libs/filament/include/viewer/ViewerGui.h | 291 ++++ package/package.json | 2 +- 315 files changed, 75833 insertions(+), 1 deletion(-) create mode 100644 package/android/libs/filament/LICENSE create mode 100644 package/android/libs/filament/README.md create mode 100644 package/android/libs/filament/include/backend/AcquiredImage.h create mode 100644 package/android/libs/filament/include/backend/BufferDescriptor.h create mode 100644 package/android/libs/filament/include/backend/CallbackHandler.h create mode 100644 package/android/libs/filament/include/backend/DriverApiForward.h create mode 100644 package/android/libs/filament/include/backend/DriverEnums.h create mode 100644 package/android/libs/filament/include/backend/Handle.h create mode 100644 package/android/libs/filament/include/backend/PipelineState.h create mode 100644 package/android/libs/filament/include/backend/PixelBufferDescriptor.h create mode 100644 package/android/libs/filament/include/backend/Platform.h create mode 100644 package/android/libs/filament/include/backend/PresentCallable.h create mode 100644 package/android/libs/filament/include/backend/Program.h create mode 100644 package/android/libs/filament/include/backend/README.md create mode 100644 package/android/libs/filament/include/backend/SamplerDescriptor.h create mode 100644 package/android/libs/filament/include/backend/TargetBufferInfo.h create mode 100644 package/android/libs/filament/include/backend/platforms/OpenGLPlatform.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformCocoaGL.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformEGL.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformEGLAndroid.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformEGLHeadless.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformGLX.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformWGL.h create mode 100644 package/android/libs/filament/include/backend/platforms/PlatformWebGL.h create mode 100644 package/android/libs/filament/include/backend/platforms/VulkanPlatform.h create mode 100644 package/android/libs/filament/include/camutils/Bookmark.h create mode 100644 package/android/libs/filament/include/camutils/Manipulator.h create mode 100644 package/android/libs/filament/include/camutils/compiler.h create mode 100644 package/android/libs/filament/include/filamat/Enums.h create mode 100644 package/android/libs/filament/include/filamat/IncludeCallback.h create mode 100644 package/android/libs/filament/include/filamat/MaterialBuilder.h create mode 100644 package/android/libs/filament/include/filamat/Package.h create mode 100644 package/android/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h create mode 100644 package/android/libs/filament/include/filament/Box.h create mode 100644 package/android/libs/filament/include/filament/BufferObject.h create mode 100644 package/android/libs/filament/include/filament/Camera.h create mode 100644 package/android/libs/filament/include/filament/Color.h create mode 100644 package/android/libs/filament/include/filament/ColorGrading.h create mode 100644 package/android/libs/filament/include/filament/ColorSpace.h create mode 100644 package/android/libs/filament/include/filament/DebugRegistry.h create mode 100644 package/android/libs/filament/include/filament/Engine.h create mode 100644 package/android/libs/filament/include/filament/Exposure.h create mode 100644 package/android/libs/filament/include/filament/Fence.h create mode 100644 package/android/libs/filament/include/filament/FilamentAPI.h create mode 100644 package/android/libs/filament/include/filament/Frustum.h create mode 100644 package/android/libs/filament/include/filament/IndexBuffer.h create mode 100644 package/android/libs/filament/include/filament/IndirectLight.h create mode 100644 package/android/libs/filament/include/filament/InstanceBuffer.h create mode 100644 package/android/libs/filament/include/filament/LightManager.h create mode 100644 package/android/libs/filament/include/filament/Material.h create mode 100644 package/android/libs/filament/include/filament/MaterialChunkType.h create mode 100644 package/android/libs/filament/include/filament/MaterialEnums.h create mode 100644 package/android/libs/filament/include/filament/MaterialInstance.h create mode 100644 package/android/libs/filament/include/filament/MorphTargetBuffer.h create mode 100644 package/android/libs/filament/include/filament/Options.h create mode 100644 package/android/libs/filament/include/filament/RenderTarget.h create mode 100644 package/android/libs/filament/include/filament/RenderableManager.h create mode 100644 package/android/libs/filament/include/filament/Renderer.h create mode 100644 package/android/libs/filament/include/filament/Scene.h create mode 100644 package/android/libs/filament/include/filament/SkinningBuffer.h create mode 100644 package/android/libs/filament/include/filament/Skybox.h create mode 100644 package/android/libs/filament/include/filament/Stream.h create mode 100644 package/android/libs/filament/include/filament/SwapChain.h create mode 100644 package/android/libs/filament/include/filament/Texture.h create mode 100644 package/android/libs/filament/include/filament/TextureSampler.h create mode 100644 package/android/libs/filament/include/filament/ToneMapper.h create mode 100644 package/android/libs/filament/include/filament/TransformManager.h create mode 100644 package/android/libs/filament/include/filament/VertexBuffer.h create mode 100644 package/android/libs/filament/include/filament/View.h create mode 100644 package/android/libs/filament/include/filament/Viewport.h create mode 100644 package/android/libs/filament/include/filameshio/MeshReader.h create mode 100644 package/android/libs/filament/include/geometry/SurfaceOrientation.h create mode 100644 package/android/libs/filament/include/geometry/TangentSpaceMesh.h create mode 100644 package/android/libs/filament/include/geometry/Transcoder.h create mode 100644 package/android/libs/filament/include/gltfio/Animator.h create mode 100644 package/android/libs/filament/include/gltfio/AssetLoader.h create mode 100644 package/android/libs/filament/include/gltfio/FilamentAsset.h create mode 100644 package/android/libs/filament/include/gltfio/FilamentInstance.h create mode 100644 package/android/libs/filament/include/gltfio/MaterialProvider.h create mode 100644 package/android/libs/filament/include/gltfio/NodeManager.h create mode 100644 package/android/libs/filament/include/gltfio/ResourceLoader.h create mode 100644 package/android/libs/filament/include/gltfio/TextureProvider.h create mode 100644 package/android/libs/filament/include/gltfio/TrsTransformManager.h create mode 100644 package/android/libs/filament/include/gltfio/materials/uberarchive.h create mode 100644 package/android/libs/filament/include/gltfio/math.h create mode 100644 package/android/libs/filament/include/ibl/Cubemap.h create mode 100644 package/android/libs/filament/include/ibl/CubemapIBL.h create mode 100644 package/android/libs/filament/include/ibl/CubemapSH.h create mode 100644 package/android/libs/filament/include/ibl/CubemapUtils.h create mode 100644 package/android/libs/filament/include/ibl/Image.h create mode 100644 package/android/libs/filament/include/ibl/utilities.h create mode 100644 package/android/libs/filament/include/image/ColorTransform.h create mode 100644 package/android/libs/filament/include/image/ImageOps.h create mode 100644 package/android/libs/filament/include/image/ImageSampler.h create mode 100644 package/android/libs/filament/include/image/Ktx1Bundle.h create mode 100644 package/android/libs/filament/include/image/LinearImage.h create mode 100644 package/android/libs/filament/include/ktxreader/Ktx1Reader.h create mode 100644 package/android/libs/filament/include/ktxreader/Ktx2Reader.h create mode 100644 package/android/libs/filament/include/math/TMatHelpers.h create mode 100644 package/android/libs/filament/include/math/TQuatHelpers.h create mode 100644 package/android/libs/filament/include/math/TVecHelpers.h create mode 100644 package/android/libs/filament/include/math/compiler.h create mode 100644 package/android/libs/filament/include/math/fast.h create mode 100644 package/android/libs/filament/include/math/half.h create mode 100644 package/android/libs/filament/include/math/mat2.h create mode 100644 package/android/libs/filament/include/math/mat3.h create mode 100644 package/android/libs/filament/include/math/mat4.h create mode 100644 package/android/libs/filament/include/math/mathfwd.h create mode 100644 package/android/libs/filament/include/math/norm.h create mode 100644 package/android/libs/filament/include/math/quat.h create mode 100644 package/android/libs/filament/include/math/scalar.h create mode 100644 package/android/libs/filament/include/math/vec2.h create mode 100644 package/android/libs/filament/include/math/vec3.h create mode 100644 package/android/libs/filament/include/math/vec4.h create mode 100644 package/android/libs/filament/include/mathio/ostream.h create mode 100644 package/android/libs/filament/include/mikktspace/mikktspace.h create mode 100644 package/android/libs/filament/include/tsl/robin_growth_policy.h create mode 100644 package/android/libs/filament/include/tsl/robin_hash.h create mode 100644 package/android/libs/filament/include/tsl/robin_map.h create mode 100644 package/android/libs/filament/include/tsl/robin_set.h create mode 100644 package/android/libs/filament/include/uberz/ArchiveEnums.h create mode 100644 package/android/libs/filament/include/uberz/ReadableArchive.h create mode 100644 package/android/libs/filament/include/uberz/WritableArchive.h create mode 100644 package/android/libs/filament/include/utils/Allocator.h create mode 100644 package/android/libs/filament/include/utils/BitmaskEnum.h create mode 100644 package/android/libs/filament/include/utils/CString.h create mode 100644 package/android/libs/filament/include/utils/CallStack.h create mode 100644 package/android/libs/filament/include/utils/Entity.h create mode 100644 package/android/libs/filament/include/utils/EntityInstance.h create mode 100644 package/android/libs/filament/include/utils/EntityManager.h create mode 100644 package/android/libs/filament/include/utils/FixedCapacityVector.h create mode 100644 package/android/libs/filament/include/utils/Invocable.h create mode 100644 package/android/libs/filament/include/utils/Log.h create mode 100644 package/android/libs/filament/include/utils/Mutex.h create mode 100644 package/android/libs/filament/include/utils/NameComponentManager.h create mode 100644 package/android/libs/filament/include/utils/Panic.h create mode 100644 package/android/libs/filament/include/utils/Path.h create mode 100644 package/android/libs/filament/include/utils/PrivateImplementation-impl.h create mode 100644 package/android/libs/filament/include/utils/PrivateImplementation.h create mode 100644 package/android/libs/filament/include/utils/SingleInstanceComponentManager.h create mode 100644 package/android/libs/filament/include/utils/Slice.h create mode 100644 package/android/libs/filament/include/utils/StructureOfArrays.h create mode 100644 package/android/libs/filament/include/utils/algorithm.h create mode 100644 package/android/libs/filament/include/utils/bitset.h create mode 100644 package/android/libs/filament/include/utils/compiler.h create mode 100644 package/android/libs/filament/include/utils/compressed_pair.h create mode 100644 package/android/libs/filament/include/utils/debug.h create mode 100644 package/android/libs/filament/include/utils/linux/Mutex.h create mode 100644 package/android/libs/filament/include/utils/memalign.h create mode 100644 package/android/libs/filament/include/utils/ostream.h create mode 100644 package/android/libs/filament/include/utils/unwindows.h create mode 100644 package/android/libs/filament/include/viewer/AutomationEngine.h create mode 100644 package/android/libs/filament/include/viewer/AutomationSpec.h create mode 100644 package/android/libs/filament/include/viewer/RemoteServer.h create mode 100644 package/android/libs/filament/include/viewer/Settings.h create mode 100644 package/android/libs/filament/include/viewer/ViewerGui.h create mode 100644 package/ios/libs/filament/LICENSE create mode 100644 package/ios/libs/filament/README.md create mode 100644 package/ios/libs/filament/include/backend/AcquiredImage.h create mode 100644 package/ios/libs/filament/include/backend/BufferDescriptor.h create mode 100644 package/ios/libs/filament/include/backend/CallbackHandler.h create mode 100644 package/ios/libs/filament/include/backend/DriverApiForward.h create mode 100644 package/ios/libs/filament/include/backend/DriverEnums.h create mode 100644 package/ios/libs/filament/include/backend/Handle.h create mode 100644 package/ios/libs/filament/include/backend/PipelineState.h create mode 100644 package/ios/libs/filament/include/backend/PixelBufferDescriptor.h create mode 100644 package/ios/libs/filament/include/backend/Platform.h create mode 100644 package/ios/libs/filament/include/backend/PresentCallable.h create mode 100644 package/ios/libs/filament/include/backend/Program.h create mode 100644 package/ios/libs/filament/include/backend/README.md create mode 100644 package/ios/libs/filament/include/backend/SamplerDescriptor.h create mode 100644 package/ios/libs/filament/include/backend/TargetBufferInfo.h create mode 100644 package/ios/libs/filament/include/backend/platforms/OpenGLPlatform.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformCocoaGL.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformEGL.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformEGLAndroid.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformEGLHeadless.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformGLX.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformWGL.h create mode 100644 package/ios/libs/filament/include/backend/platforms/PlatformWebGL.h create mode 100644 package/ios/libs/filament/include/backend/platforms/VulkanPlatform.h create mode 100644 package/ios/libs/filament/include/camutils/Bookmark.h create mode 100644 package/ios/libs/filament/include/camutils/Manipulator.h create mode 100644 package/ios/libs/filament/include/camutils/compiler.h create mode 100644 package/ios/libs/filament/include/filamat/Enums.h create mode 100644 package/ios/libs/filament/include/filamat/IncludeCallback.h create mode 100644 package/ios/libs/filament/include/filamat/MaterialBuilder.h create mode 100644 package/ios/libs/filament/include/filamat/Package.h create mode 100644 package/ios/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h create mode 100644 package/ios/libs/filament/include/filament/Box.h create mode 100644 package/ios/libs/filament/include/filament/BufferObject.h create mode 100644 package/ios/libs/filament/include/filament/Camera.h create mode 100644 package/ios/libs/filament/include/filament/Color.h create mode 100644 package/ios/libs/filament/include/filament/ColorGrading.h create mode 100644 package/ios/libs/filament/include/filament/ColorSpace.h create mode 100644 package/ios/libs/filament/include/filament/DebugRegistry.h create mode 100644 package/ios/libs/filament/include/filament/Engine.h create mode 100644 package/ios/libs/filament/include/filament/Exposure.h create mode 100644 package/ios/libs/filament/include/filament/Fence.h create mode 100644 package/ios/libs/filament/include/filament/FilamentAPI.h create mode 100644 package/ios/libs/filament/include/filament/Frustum.h create mode 100644 package/ios/libs/filament/include/filament/IndexBuffer.h create mode 100644 package/ios/libs/filament/include/filament/IndirectLight.h create mode 100644 package/ios/libs/filament/include/filament/InstanceBuffer.h create mode 100644 package/ios/libs/filament/include/filament/LightManager.h create mode 100644 package/ios/libs/filament/include/filament/Material.h create mode 100644 package/ios/libs/filament/include/filament/MaterialChunkType.h create mode 100644 package/ios/libs/filament/include/filament/MaterialEnums.h create mode 100644 package/ios/libs/filament/include/filament/MaterialInstance.h create mode 100644 package/ios/libs/filament/include/filament/MorphTargetBuffer.h create mode 100644 package/ios/libs/filament/include/filament/Options.h create mode 100644 package/ios/libs/filament/include/filament/RenderTarget.h create mode 100644 package/ios/libs/filament/include/filament/RenderableManager.h create mode 100644 package/ios/libs/filament/include/filament/Renderer.h create mode 100644 package/ios/libs/filament/include/filament/Scene.h create mode 100644 package/ios/libs/filament/include/filament/SkinningBuffer.h create mode 100644 package/ios/libs/filament/include/filament/Skybox.h create mode 100644 package/ios/libs/filament/include/filament/Stream.h create mode 100644 package/ios/libs/filament/include/filament/SwapChain.h create mode 100644 package/ios/libs/filament/include/filament/Texture.h create mode 100644 package/ios/libs/filament/include/filament/TextureSampler.h create mode 100644 package/ios/libs/filament/include/filament/ToneMapper.h create mode 100644 package/ios/libs/filament/include/filament/TransformManager.h create mode 100644 package/ios/libs/filament/include/filament/VertexBuffer.h create mode 100644 package/ios/libs/filament/include/filament/View.h create mode 100644 package/ios/libs/filament/include/filament/Viewport.h create mode 100644 package/ios/libs/filament/include/filameshio/MeshReader.h create mode 100644 package/ios/libs/filament/include/geometry/SurfaceOrientation.h create mode 100644 package/ios/libs/filament/include/geometry/TangentSpaceMesh.h create mode 100644 package/ios/libs/filament/include/geometry/Transcoder.h create mode 100644 package/ios/libs/filament/include/gltfio/Animator.h create mode 100644 package/ios/libs/filament/include/gltfio/AssetLoader.h create mode 100644 package/ios/libs/filament/include/gltfio/FilamentAsset.h create mode 100644 package/ios/libs/filament/include/gltfio/FilamentInstance.h create mode 100644 package/ios/libs/filament/include/gltfio/MaterialProvider.h create mode 100644 package/ios/libs/filament/include/gltfio/NodeManager.h create mode 100644 package/ios/libs/filament/include/gltfio/ResourceLoader.h create mode 100644 package/ios/libs/filament/include/gltfio/TextureProvider.h create mode 100644 package/ios/libs/filament/include/gltfio/TrsTransformManager.h create mode 100644 package/ios/libs/filament/include/gltfio/materials/uberarchive.h create mode 100644 package/ios/libs/filament/include/gltfio/math.h create mode 100644 package/ios/libs/filament/include/ibl/Cubemap.h create mode 100644 package/ios/libs/filament/include/ibl/CubemapIBL.h create mode 100644 package/ios/libs/filament/include/ibl/CubemapSH.h create mode 100644 package/ios/libs/filament/include/ibl/CubemapUtils.h create mode 100644 package/ios/libs/filament/include/ibl/Image.h create mode 100644 package/ios/libs/filament/include/ibl/utilities.h create mode 100644 package/ios/libs/filament/include/image/ColorTransform.h create mode 100644 package/ios/libs/filament/include/image/ImageOps.h create mode 100644 package/ios/libs/filament/include/image/ImageSampler.h create mode 100644 package/ios/libs/filament/include/image/Ktx1Bundle.h create mode 100644 package/ios/libs/filament/include/image/LinearImage.h create mode 100644 package/ios/libs/filament/include/ktxreader/Ktx1Reader.h create mode 100644 package/ios/libs/filament/include/ktxreader/Ktx2Reader.h create mode 100644 package/ios/libs/filament/include/math/TMatHelpers.h create mode 100644 package/ios/libs/filament/include/math/TQuatHelpers.h create mode 100644 package/ios/libs/filament/include/math/TVecHelpers.h create mode 100644 package/ios/libs/filament/include/math/compiler.h create mode 100644 package/ios/libs/filament/include/math/fast.h create mode 100644 package/ios/libs/filament/include/math/half.h create mode 100644 package/ios/libs/filament/include/math/mat2.h create mode 100644 package/ios/libs/filament/include/math/mat3.h create mode 100644 package/ios/libs/filament/include/math/mat4.h create mode 100644 package/ios/libs/filament/include/math/mathfwd.h create mode 100644 package/ios/libs/filament/include/math/norm.h create mode 100644 package/ios/libs/filament/include/math/quat.h create mode 100644 package/ios/libs/filament/include/math/scalar.h create mode 100644 package/ios/libs/filament/include/math/vec2.h create mode 100644 package/ios/libs/filament/include/math/vec3.h create mode 100644 package/ios/libs/filament/include/math/vec4.h create mode 100644 package/ios/libs/filament/include/mathio/ostream.h create mode 100644 package/ios/libs/filament/include/mikktspace/mikktspace.h create mode 100644 package/ios/libs/filament/include/tsl/robin_growth_policy.h create mode 100644 package/ios/libs/filament/include/tsl/robin_hash.h create mode 100644 package/ios/libs/filament/include/tsl/robin_map.h create mode 100644 package/ios/libs/filament/include/tsl/robin_set.h create mode 100644 package/ios/libs/filament/include/uberz/ArchiveEnums.h create mode 100644 package/ios/libs/filament/include/uberz/ReadableArchive.h create mode 100644 package/ios/libs/filament/include/uberz/WritableArchive.h create mode 100644 package/ios/libs/filament/include/utils/Allocator.h create mode 100644 package/ios/libs/filament/include/utils/BitmaskEnum.h create mode 100644 package/ios/libs/filament/include/utils/CString.h create mode 100644 package/ios/libs/filament/include/utils/CallStack.h create mode 100644 package/ios/libs/filament/include/utils/Entity.h create mode 100644 package/ios/libs/filament/include/utils/EntityInstance.h create mode 100644 package/ios/libs/filament/include/utils/EntityManager.h create mode 100644 package/ios/libs/filament/include/utils/FixedCapacityVector.h create mode 100644 package/ios/libs/filament/include/utils/Invocable.h create mode 100644 package/ios/libs/filament/include/utils/Log.h create mode 100644 package/ios/libs/filament/include/utils/Mutex.h create mode 100644 package/ios/libs/filament/include/utils/NameComponentManager.h create mode 100644 package/ios/libs/filament/include/utils/Panic.h create mode 100644 package/ios/libs/filament/include/utils/Path.h create mode 100644 package/ios/libs/filament/include/utils/PrivateImplementation-impl.h create mode 100644 package/ios/libs/filament/include/utils/PrivateImplementation.h create mode 100644 package/ios/libs/filament/include/utils/SingleInstanceComponentManager.h create mode 100644 package/ios/libs/filament/include/utils/Slice.h create mode 100644 package/ios/libs/filament/include/utils/StructureOfArrays.h create mode 100644 package/ios/libs/filament/include/utils/algorithm.h create mode 100644 package/ios/libs/filament/include/utils/bitset.h create mode 100644 package/ios/libs/filament/include/utils/compiler.h create mode 100644 package/ios/libs/filament/include/utils/compressed_pair.h create mode 100644 package/ios/libs/filament/include/utils/debug.h create mode 100644 package/ios/libs/filament/include/utils/generic/Mutex.h create mode 100644 package/ios/libs/filament/include/utils/memalign.h create mode 100644 package/ios/libs/filament/include/utils/ostream.h create mode 100644 package/ios/libs/filament/include/utils/unwindows.h create mode 100644 package/ios/libs/filament/include/viewer/AutomationEngine.h create mode 100644 package/ios/libs/filament/include/viewer/AutomationSpec.h create mode 100644 package/ios/libs/filament/include/viewer/RemoteServer.h create mode 100644 package/ios/libs/filament/include/viewer/Settings.h create mode 100644 package/ios/libs/filament/include/viewer/ViewerGui.h diff --git a/package/android/libs/filament/LICENSE b/package/android/libs/filament/LICENSE new file mode 100644 index 00000000..73774b41 --- /dev/null +++ b/package/android/libs/filament/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 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. diff --git a/package/android/libs/filament/README.md b/package/android/libs/filament/README.md new file mode 100644 index 00000000..79ec596b --- /dev/null +++ b/package/android/libs/filament/README.md @@ -0,0 +1,182 @@ +# Filament + +This package contains several executables and libraries you can use to build applications using +Filament. Latest versions are available on the [project page](https://github.com/google/filament). + +## Binaries + +- `cmgen`, Image-based lighting asset generator +- `filamesh`, Mesh converter +- `glslminifier`, Tool to minify GLSL shaders +- `gltf_viewer`, glTF 2.0 viewer that lets you explore many features of Filament +- `matc`, Material compiler +- `material_sandbox`, simple mesh viewer that lets you explore material and lighting features +- `matinfo`, Displays information about materials compiled with `matc` +- `mipgen`, Generates a series of miplevels from a source image. +- `normal-blending`, Tool to blend normal maps +- `resgen`, Tool to convert files into binary resources to be embedded at compie time +- `roughness-prefilter`, Pre-filters a roughness map from a normal map to reduce aliasing +- `specular-color`, Computes the specular color of conductors based on spectral data + +You can refer to the individual documentation files in `docs/` for more information. + +## Libraries + +Filament is distributed as a set of static libraries you must link against: + +- `backend`, Required, implements all backends +- `bluegl`, Required to render with OpenGL or OpenGL ES +- `bluevk`, Required to render with Vulkan +- `filabridge`, Support library for Filament +- `filaflat`, Support library for Filament +- `filament`, Main Filament library +- `backend`, Filament render backend library +- `ibl`, Image-based lighting support library +- `utils`, Support library for Filament +- `geometry`, Geometry helper library for Filament +- `smol-v`, SPIR-V compression library, used only with Vulkan support + +To use Filament from Java you must use the following two libraries instead: +- `filament-java.jar`, Contains Filament's Java classes +- `filament-jni`, Filament's JNI bindings + +To link against debug builds of Filament, you must also link against: + +- `matdbg`, Support library that adds an interactive web-based debugger to Filament + +To use the Vulkan backend on macOS you must install the LunarG SDK, enable "System Global +Components", and reboot your machine. + +The easiest way to install those files is to use the macOS +[LunarG Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) installer. + +## Linking against Filament + +This walkthrough will get you successfully compiling and linking native code +against Filament with minimum dependencies. + +To start, download Filament's [latest binary release](https://github.com/google/filament/releases) +and extract into a directory of your choosing. Binary releases are suffixed +with the platform name, for example, `filament-20181009-linux.tgz`. + +Create a file, `main.cpp`, in the same directory with the following contents: + +```c++ +#include +#include + +using namespace filament; + +int main(int argc, char** argv) +{ + Engine *engine = Engine::create(); + engine->destroy(&engine); + return 0; +} +``` + +The directory should look like: + +``` +|-- README.md +|-- bin +|-- docs +|-- include +|-- lib +|-- main.cpp +``` + +We'll use a platform-specific Makefile to compile and link `main.cpp` with Filament's libraries. +Copy your platform's Makefile below into a `Makefile` inside the same directory. + +### Linux + +```make +FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl +CC=clang++ + +main: main.o + $(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) -lpthread -lc++ -ldl -o main + +main.o: main.cpp + $(CC) -Iinclude/ -std=c++17 -pthread -c main.cpp + +clean: + rm -f main main.o + +.PHONY: clean +``` + +### macOS + +```make +FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl +FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo +CC=clang++ + +main: main.o + $(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main + +main.o: main.cpp + $(CC) -Iinclude/ -std=c++17 -c main.cpp + +clean: + rm -f main main.o + +.PHONY: clean +``` + +### Windows + +Note that the static libraries distributed for Windows include several +variants: mt, md, mtd, mdd. These correspond to the [run-time library +flags](https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=vs-2017) +`/MT`, `/MD`, `/MTd`, and `/MDd`, respectively. Here we use the mt variant. For the debug variants, +be sure to also include `matdbg.lib` in `FILAMENT_LIBS`. + +When building Filament from source, the `USE_STATIC_CRT` CMake option can be +used to change the run-time library version. + +```make +FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \ + utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib +CC=cl.exe + +main.exe: main.obj + $(CC) main.obj /link /libpath:"lib\\x86_64\\mt\\" $(FILAMENT_LIBS) \ + gdi32.lib user32.lib opengl32.lib + +main.obj: main.cpp + $(CC) /MT /Iinclude\\ /std:c++17 /c main.cpp + +clean: + del main.exe main.obj + +.PHONY: clean +``` + +### Compiling + +You should be able to invoke `make` and run the executable successfully: + +``` +$ make +$ ./main +FEngine (64 bits) created at 0x106471000 (threading is enabled) +``` + +On Windows, you'll need to open up a Visual Studio Native Tools Command Prompt +and invoke `nmake` instead of `make`. + + +### Generating C++ documentation + +To generate the documentation you must first install `doxygen` and `graphviz`, then run the +following commands: + +```shell +cd filament/filament +doxygen docs/doxygen/filament.doxygen +``` + +Finally simply open `docs/html/index.html` in your web browser. diff --git a/package/android/libs/filament/include/backend/AcquiredImage.h b/package/android/libs/filament/include/backend/AcquiredImage.h new file mode 100644 index 00000000..fec27a53 --- /dev/null +++ b/package/android/libs/filament/include/backend/AcquiredImage.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H +#define TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H + +#include + +namespace filament::backend { + +class CallbackHandler; + +// This lightweight POD allows us to bundle the state required to process an ACQUIRED stream. +// Since these types of external images need to be moved around and queued up, an encapsulation is +// very useful. + +struct AcquiredImage { + void* image = nullptr; + backend::StreamCallback callback = nullptr; + void* userData = nullptr; + CallbackHandler* handler = nullptr; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H diff --git a/package/android/libs/filament/include/backend/BufferDescriptor.h b/package/android/libs/filament/include/backend/BufferDescriptor.h new file mode 100644 index 00000000..ebb57537 --- /dev/null +++ b/package/android/libs/filament/include/backend/BufferDescriptor.h @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H + +#include +#include + +#include + +namespace filament::backend { + +class CallbackHandler; + +/** + * A CPU memory-buffer descriptor, typically used to transfer data from the CPU to the GPU. + * + * A BufferDescriptor owns the memory buffer it references, therefore BufferDescriptor cannot + * be copied, but can be moved. + * + * BufferDescriptor releases ownership of the memory-buffer when it's destroyed. + */ +class UTILS_PUBLIC BufferDescriptor { +public: + /** + * Callback used to destroy the buffer data. + * Guarantees: + * Called on the main filament thread. + * + * Limitations: + * Must be lightweight. + * Must not call filament APIs. + */ + using Callback = void(*)(void* buffer, size_t size, void* user); + + //! creates an empty descriptor + BufferDescriptor() noexcept = default; + + //! calls the callback to advertise BufferDescriptor no-longer owns the buffer + ~BufferDescriptor() noexcept { + if (mCallback) { + mCallback(buffer, size, mUser); + } + } + + BufferDescriptor(const BufferDescriptor& rhs) = delete; + BufferDescriptor& operator=(const BufferDescriptor& rhs) = delete; + + BufferDescriptor(BufferDescriptor&& rhs) noexcept + : buffer(rhs.buffer), size(rhs.size), + mCallback(rhs.mCallback), mUser(rhs.mUser), mHandler(rhs.mHandler) { + rhs.buffer = nullptr; + rhs.mCallback = nullptr; + } + + BufferDescriptor& operator=(BufferDescriptor&& rhs) noexcept { + if (this != &rhs) { + buffer = rhs.buffer; + size = rhs.size; + mCallback = rhs.mCallback; + mUser = rhs.mUser; + mHandler = rhs.mHandler; + rhs.buffer = nullptr; + rhs.mCallback = nullptr; + } + return *this; + } + + /** + * Creates a BufferDescriptor that references a CPU memory-buffer + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param callback A callback used to release the CPU buffer from this BufferDescriptor + * @param user An opaque user pointer passed to the callback function when it's called + */ + BufferDescriptor(void const* buffer, size_t size, + Callback callback = nullptr, void* user = nullptr) noexcept + : buffer(const_cast(buffer)), size(size), mCallback(callback), mUser(user) { + } + + /** + * Creates a BufferDescriptor that references a CPU memory-buffer + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param callback A callback used to release the CPU buffer from this BufferDescriptor + * @param user An opaque user pointer passed to the callback function when it's called + */ + BufferDescriptor(void const* buffer, size_t size, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : buffer(const_cast(buffer)), size(size), + mCallback(callback), mUser(user), mHandler(handler) { + } + + // -------------------------------------------------------------------------------------------- + + /** + * Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed + * by pointer as the callback. e.g.: + * auto bd = BufferDescriptor::make(buffer, size, foo); + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param handler Handler to use to dispatch the callback, or nullptr for the default handler + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make(void const* buffer, size_t size, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { + buffer, size, + handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); + }, data + }; + } + + /** + * Helper to create a BufferDescriptor that uses a functor as the callback. + * + * Caveats: + * - DO NOT CALL setCallback() when using this helper. + * - This make a heap allocation + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param functor functor of type f(void const* buffer, size_t size) + * @param handler Handler to use to dispatch the callback, or nullptr for the default handler + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make(void const* buffer, size_t size, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { + buffer, size, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, + new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + + /** + * Set or replace the release callback function + * @param callback The new callback function + * @param user An opaque user pointer passed to the callbeck function when it's called + */ + void setCallback(Callback callback, void* user = nullptr) noexcept { + this->mCallback = callback; + this->mUser = user; + this->mHandler = nullptr; + } + + /** + * Set or replace the release callback function + * @param handler The Handler to use to dispatch the callback + * @param callback The new callback function + * @param user An opaque user pointer passed to the callbeck function when it's called + */ + void setCallback(CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept { + mCallback = callback; + mUser = user; + mHandler = handler; + } + + //! Returns whether a release callback is set + bool hasCallback() const noexcept { return mCallback != nullptr; } + + //! Returns the currently set release callback function + Callback getCallback() const noexcept { + return mCallback; + } + + //! Returns the handler for this callback or nullptr if the default handler is to be used. + CallbackHandler* getHandler() const noexcept { + return mHandler; + } + + //! Returns the user opaque pointer associated to this BufferDescriptor + void* getUser() const noexcept { + return mUser; + } + + //! CPU memory-buffer virtual address + void* buffer = nullptr; + + //! CPU memory-buffer size in bytes + size_t size = 0; + +private: + // callback when the buffer is consumed. + Callback mCallback = nullptr; + void* mUser = nullptr; + CallbackHandler* mHandler = nullptr; +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::BufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H diff --git a/package/android/libs/filament/include/backend/CallbackHandler.h b/package/android/libs/filament/include/backend/CallbackHandler.h new file mode 100644 index 00000000..036031a9 --- /dev/null +++ b/package/android/libs/filament/include/backend/CallbackHandler.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H +#define TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H + +namespace filament::backend { + +/** + * A generic interface to dispatch callbacks. + * + * All APIs that take a callback as argument also take a + * CallbackHandler* which is used to dispatch the + * callback: CallbackHandler::post() method is called from a service thread as soon + * as possible (this will NEVER be the main thread), CallbackHandler::post() + * is responsible for scheduling the callback onto the thread the + * user desires. + * + * This is intended to make callbacks interoperate with + * the platform/OS's own messaging system. + * + * CallbackHandler* can always be nullptr in which case the default handler is used. The + * default handler always dispatches callbacks on filament's main thread opportunistically. + * + * Life time: + * --------- + * + * Filament make no attempts to manage the life time of the CallbackHandler* and never takes + * ownership. + * In particular, this means that the CallbackHandler instance must stay valid until all + * pending callbacks are been dispatched. + * + * Similarly, when shutting down filament, care must be taken to ensure that all pending callbacks + * that might access filament's state have been dispatched. Filament can no longer ensure this + * because callback execution is the responsibility of the CallbackHandler, which is external to + * filament. + * Typically, the concrete CallbackHandler would have a mechanism to drain and/or wait for all + * callbacks to be processed. + * + */ +class CallbackHandler { +public: + using Callback = void(*)(void* user); + + /** + * Schedules the callback to be called onto the appropriate thread. + * Typically this will be the application's main thead. + * + * Must be thread-safe. + */ + virtual void post(void* user, Callback callback) = 0; + +protected: + virtual ~CallbackHandler() = default; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H diff --git a/package/android/libs/filament/include/backend/DriverApiForward.h b/package/android/libs/filament/include/backend/DriverApiForward.h new file mode 100644 index 00000000..9cc56c03 --- /dev/null +++ b/package/android/libs/filament/include/backend/DriverApiForward.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H +#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H + +namespace filament::backend { + +class CommandStream; + +using DriverApi = CommandStream; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H diff --git a/package/android/libs/filament/include/backend/DriverEnums.h b/package/android/libs/filament/include/backend/DriverEnums.h new file mode 100644 index 00000000..c41d1b83 --- /dev/null +++ b/package/android/libs/filament/include/backend/DriverEnums.h @@ -0,0 +1,1269 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_DRIVERENUMS_H +#define TNT_FILAMENT_BACKEND_DRIVERENUMS_H + +#include +#include // Because we define ERROR in the FenceStatus enum. + +#include + +#include + +#include + +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers + +#include +#include + +/** + * Types and enums used by filament's driver. + * + * Effectively these types are public but should not be used directly. Instead use public classes + * internal redeclaration of these types. + * For e.g. Use Texture::Sampler instead of filament::SamplerType. + */ +namespace filament::backend { + +/** + * Requests a SwapChain with an alpha channel. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1; + +/** + * This flag indicates that the swap chain may be used as a source surface + * for reading back render results. This config flag must be set when creating + * any SwapChain that will be used as the source for a blit operation. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2; + +/** + * Indicates that the native X11 window is an XCB window rather than an XLIB window. + * This is ignored on non-Linux platforms and in builds that support only one X11 API. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4; + +/** + * Indicates that the native window is a CVPixelBufferRef. + * + * This is only supported by the Metal backend. The CVPixelBuffer must be in the + * kCVPixelFormatType_32BGRA format. + * + * It is not necessary to add an additional retain call before passing the pixel buffer to + * Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and + * CVPixelBufferRelease when the swap chain is destroyed. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8; + +/** + * Indicates that the SwapChain must automatically perform linear to srgb encoding. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10; + +/** + * Indicates that the SwapChain should also contain a stencil component. + */ +static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = 0x20; + + +static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES. +static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3. +static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects. +static constexpr size_t MAX_SSBO_COUNT = 4; // This is guaranteed by OpenGL ES. + +// Per feature level caps +// Use (int)FeatureLevel to index this array +static constexpr struct { + const size_t MAX_VERTEX_SAMPLER_COUNT; + const size_t MAX_FRAGMENT_SAMPLER_COUNT; +} FEATURE_LEVEL_CAPS[4] = { + { 0, 0 }, // do not use + { 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal + { 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal + { 31, 31 }, // guaranteed by Metal +}; + +static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT, + "The number of buffer objects that can be attached to a VertexBuffer must be " + "less than or equal to the maximum number of vertex attributes."); + +static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 10; // This is guaranteed by OpenGL ES. +static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES. + +/** + * Defines the backend's feature levels. + */ +enum class FeatureLevel : uint8_t { + FEATURE_LEVEL_0 = 0, //!< OpenGL ES 2.0 features + FEATURE_LEVEL_1, //!< OpenGL ES 3.0 features (default) + FEATURE_LEVEL_2, //!< OpenGL ES 3.1 features + 16 textures units + cubemap arrays + FEATURE_LEVEL_3 //!< OpenGL ES 3.1 features + 31 textures units + cubemap arrays +}; + +/** + * Selects which driver a particular Engine should use. + */ +enum class Backend : uint8_t { + DEFAULT = 0, //!< Automatically selects an appropriate driver for the platform. + OPENGL = 1, //!< Selects the OpenGL/ES driver (default on Android) + VULKAN = 2, //!< Selects the Vulkan driver if the platform supports it (default on Linux/Windows) + METAL = 3, //!< Selects the Metal driver if the platform supports it (default on MacOS/iOS). + NOOP = 4, //!< Selects the no-op driver for testing purposes. +}; + +static constexpr const char* backendToString(Backend backend) { + switch (backend) { + case Backend::NOOP: + return "Noop"; + case Backend::OPENGL: + return "OpenGL"; + case Backend::VULKAN: + return "Vulkan"; + case Backend::METAL: + return "Metal"; + default: + return "Unknown"; + } +} + +/** + * Defines the shader language. Similar to the above backend enum, but the OpenGL backend can select + * between two shader languages: ESSL 1.0 and ESSL 3.0. + */ +enum class ShaderLanguage { + ESSL1 = 0, + ESSL3 = 1, + SPIRV = 2, + MSL = 3, +}; + +static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) { + switch (shaderLanguage) { + case ShaderLanguage::ESSL1: + return "ESSL 1.0"; + case ShaderLanguage::ESSL3: + return "ESSL 3.0"; + case ShaderLanguage::SPIRV: + return "SPIR-V"; + case ShaderLanguage::MSL: + return "MSL"; + } +} + +/** + * Bitmask for selecting render buffers + */ +enum class TargetBufferFlags : uint32_t { + NONE = 0x0u, //!< No buffer selected. + COLOR0 = 0x00000001u, //!< Color buffer selected. + COLOR1 = 0x00000002u, //!< Color buffer selected. + COLOR2 = 0x00000004u, //!< Color buffer selected. + COLOR3 = 0x00000008u, //!< Color buffer selected. + COLOR4 = 0x00000010u, //!< Color buffer selected. + COLOR5 = 0x00000020u, //!< Color buffer selected. + COLOR6 = 0x00000040u, //!< Color buffer selected. + COLOR7 = 0x00000080u, //!< Color buffer selected. + + COLOR = COLOR0, //!< \deprecated + COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7, + DEPTH = 0x10000000u, //!< Depth buffer selected. + STENCIL = 0x20000000u, //!< Stencil buffer selected. + DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. + ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. +}; + +inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept { + if (index == 0u) return TargetBufferFlags::COLOR0; + if (index == 1u) return TargetBufferFlags::COLOR1; + if (index == 2u) return TargetBufferFlags::COLOR2; + if (index == 3u) return TargetBufferFlags::COLOR3; + if (index == 4u) return TargetBufferFlags::COLOR4; + if (index == 5u) return TargetBufferFlags::COLOR5; + if (index == 6u) return TargetBufferFlags::COLOR6; + if (index == 7u) return TargetBufferFlags::COLOR7; + if (index == 8u) return TargetBufferFlags::DEPTH; + if (index == 9u) return TargetBufferFlags::STENCIL; + return TargetBufferFlags::NONE; +} + +/** + * Frequency at which a buffer is expected to be modified and used. This is used as an hint + * for the driver to make better decisions about managing memory internally. + */ +enum class BufferUsage : uint8_t { + STATIC, //!< content modified once, used many times + DYNAMIC, //!< content modified frequently, used many times +}; + +/** + * Defines a viewport, which is the origin and extent of the clip-space. + * All drawing is clipped to the viewport. + */ +struct Viewport { + int32_t left; //!< left coordinate in window space. + int32_t bottom; //!< bottom coordinate in window space. + uint32_t width; //!< width in pixels + uint32_t height; //!< height in pixels + //! get the right coordinate in window space of the viewport + int32_t right() const noexcept { return left + int32_t(width); } + //! get the top coordinate in window space of the viewport + int32_t top() const noexcept { return bottom + int32_t(height); } +}; + + +/** + * Specifies the mapping of the near and far clipping plane to window coordinates. + */ +struct DepthRange { + float near = 0.0f; //!< mapping of the near plane to window coordinates. + float far = 1.0f; //!< mapping of the far plane to window coordinates. +}; + +/** + * Error codes for Fence::wait() + * @see Fence, Fence::wait() + */ +enum class FenceStatus : int8_t { + ERROR = -1, //!< An error occurred. The Fence condition is not satisfied. + CONDITION_SATISFIED = 0, //!< The Fence condition is satisfied. + TIMEOUT_EXPIRED = 1, //!< wait()'s timeout expired. The Fence condition is not satisfied. +}; + +/** + * Status codes for sync objects + */ +enum class SyncStatus : int8_t { + ERROR = -1, //!< An error occurred. The Sync is not signaled. + SIGNALED = 0, //!< The Sync is signaled. + NOT_SIGNALED = 1, //!< The Sync is not signaled yet +}; + +static constexpr uint64_t FENCE_WAIT_FOR_EVER = uint64_t(-1); + +/** + * Shader model. + * + * These enumerants are used across all backends and refer to a level of functionality and quality. + * + * For example, the OpenGL backend returns `MOBILE` if it supports OpenGL ES, or `DESKTOP` if it + * supports Desktop OpenGL, this is later used to select the proper shader. + * + * Shader quality vs. performance is also affected by ShaderModel. + */ +enum class ShaderModel : uint8_t { + MOBILE = 1, //!< Mobile level functionality + DESKTOP = 2, //!< Desktop level functionality +}; +static constexpr size_t SHADER_MODEL_COUNT = 2; + +/** + * Primitive types + */ +enum class PrimitiveType : uint8_t { + // don't change the enums values (made to match GL) + POINTS = 0, //!< points + LINES = 1, //!< lines + LINE_STRIP = 3, //!< line strip + TRIANGLES = 4, //!< triangles + TRIANGLE_STRIP = 5 //!< triangle strip +}; + +/** + * Supported uniform types + */ +enum class UniformType : uint8_t { + BOOL, + BOOL2, + BOOL3, + BOOL4, + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4, + INT, + INT2, + INT3, + INT4, + UINT, + UINT2, + UINT3, + UINT4, + MAT3, //!< a 3x3 float matrix + MAT4, //!< a 4x4 float matrix + STRUCT +}; + +/** + * Supported constant parameter types + */ + enum class ConstantType : uint8_t { + INT, + FLOAT, + BOOL +}; + +enum class Precision : uint8_t { + LOW, + MEDIUM, + HIGH, + DEFAULT +}; + +/** + * Shader compiler priority queue + */ +enum class CompilerPriorityQueue : uint8_t { + HIGH, + LOW +}; + +//! Texture sampler type +enum class SamplerType : uint8_t { + SAMPLER_2D, //!< 2D texture + SAMPLER_2D_ARRAY, //!< 2D array texture + SAMPLER_CUBEMAP, //!< Cube map texture + SAMPLER_EXTERNAL, //!< External texture + SAMPLER_3D, //!< 3D texture + SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2) +}; + +//! Subpass type +enum class SubpassType : uint8_t { + SUBPASS_INPUT +}; + +//! Texture sampler format +enum class SamplerFormat : uint8_t { + INT = 0, //!< signed integer sampler + UINT = 1, //!< unsigned integer sampler + FLOAT = 2, //!< float sampler + SHADOW = 3 //!< shadow sampler (PCF) +}; + +/** + * Supported element types + */ +enum class ElementType : uint8_t { + BYTE, + BYTE2, + BYTE3, + BYTE4, + UBYTE, + UBYTE2, + UBYTE3, + UBYTE4, + SHORT, + SHORT2, + SHORT3, + SHORT4, + USHORT, + USHORT2, + USHORT3, + USHORT4, + INT, + UINT, + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4, + HALF, + HALF2, + HALF3, + HALF4, +}; + +//! Buffer object binding type +enum class BufferObjectBinding : uint8_t { + VERTEX, + UNIFORM, + SHADER_STORAGE +}; + +//! Face culling Mode +enum class CullingMode : uint8_t { + NONE, //!< No culling, front and back faces are visible + FRONT, //!< Front face culling, only back faces are visible + BACK, //!< Back face culling, only front faces are visible + FRONT_AND_BACK //!< Front and Back, geometry is not visible +}; + +//! Pixel Data Format +enum class PixelDataFormat : uint8_t { + R, //!< One Red channel, float + R_INTEGER, //!< One Red channel, integer + RG, //!< Two Red and Green channels, float + RG_INTEGER, //!< Two Red and Green channels, integer + RGB, //!< Three Red, Green and Blue channels, float + RGB_INTEGER, //!< Three Red, Green and Blue channels, integer + RGBA, //!< Four Red, Green, Blue and Alpha channels, float + RGBA_INTEGER, //!< Four Red, Green, Blue and Alpha channels, integer + UNUSED, // used to be rgbm + DEPTH_COMPONENT, //!< Depth, 16-bit or 24-bits usually + DEPTH_STENCIL, //!< Two Depth (24-bits) + Stencil (8-bits) channels + ALPHA //! One Alpha channel, float +}; + +//! Pixel Data Type +enum class PixelDataType : uint8_t { + UBYTE, //!< unsigned byte + BYTE, //!< signed byte + USHORT, //!< unsigned short (16-bit) + SHORT, //!< signed short (16-bit) + UINT, //!< unsigned int (32-bit) + INT, //!< signed int (32-bit) + HALF, //!< half-float (16-bit float) + FLOAT, //!< float (32-bits float) + COMPRESSED, //!< compressed pixels, @see CompressedPixelDataType + UINT_10F_11F_11F_REV, //!< three low precision floating-point numbers + USHORT_565, //!< unsigned int (16-bit), encodes 3 RGB channels + UINT_2_10_10_10_REV, //!< unsigned normalized 10 bits RGB, 2 bits alpha +}; + +//! Compressed pixel data types +enum class CompressedPixelDataType : uint16_t { + // Mandatory in GLES 3.0 and GL 4.3 + EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, + ETC2_RGB8, ETC2_SRGB8, + ETC2_RGB8_A1, ETC2_SRGB8_A1, + ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, + + // Available everywhere except Android/iOS + DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, + DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, + + // ASTC formats are available with a GLES extension + RGBA_ASTC_4x4, + RGBA_ASTC_5x4, + RGBA_ASTC_5x5, + RGBA_ASTC_6x5, + RGBA_ASTC_6x6, + RGBA_ASTC_8x5, + RGBA_ASTC_8x6, + RGBA_ASTC_8x8, + RGBA_ASTC_10x5, + RGBA_ASTC_10x6, + RGBA_ASTC_10x8, + RGBA_ASTC_10x10, + RGBA_ASTC_12x10, + RGBA_ASTC_12x12, + SRGB8_ALPHA8_ASTC_4x4, + SRGB8_ALPHA8_ASTC_5x4, + SRGB8_ALPHA8_ASTC_5x5, + SRGB8_ALPHA8_ASTC_6x5, + SRGB8_ALPHA8_ASTC_6x6, + SRGB8_ALPHA8_ASTC_8x5, + SRGB8_ALPHA8_ASTC_8x6, + SRGB8_ALPHA8_ASTC_8x8, + SRGB8_ALPHA8_ASTC_10x5, + SRGB8_ALPHA8_ASTC_10x6, + SRGB8_ALPHA8_ASTC_10x8, + SRGB8_ALPHA8_ASTC_10x10, + SRGB8_ALPHA8_ASTC_12x10, + SRGB8_ALPHA8_ASTC_12x12, + + // RGTC formats available with a GLES extension + RED_RGTC1, // BC4 unsigned + SIGNED_RED_RGTC1, // BC4 signed + RED_GREEN_RGTC2, // BC5 unsigned + SIGNED_RED_GREEN_RGTC2, // BC5 signed + + // BPTC formats available with a GLES extension + RGB_BPTC_SIGNED_FLOAT, // BC6H signed + RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned + RGBA_BPTC_UNORM, // BC7 + SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB +}; + +/** Supported texel formats + * These formats are typically used to specify a texture's internal storage format. + * + * Enumerants syntax format + * ======================== + * + * `[components][size][type]` + * + * `components` : List of stored components by this format.\n + * `size` : Size in bit of each component.\n + * `type` : Type this format is stored as.\n + * + * + * Name | Component + * :--------|:------------------------------- + * R | Linear Red + * RG | Linear Red, Green + * RGB | Linear Red, Green, Blue + * RGBA | Linear Red, Green Blue, Alpha + * SRGB | sRGB encoded Red, Green, Blue + * DEPTH | Depth + * STENCIL | Stencil + * + * \n + * Name | Type + * :--------|:--------------------------------------------------- + * (none) | Unsigned Normalized Integer [0, 1] + * _SNORM | Signed Normalized Integer [-1, 1] + * UI | Unsigned Integer @f$ [0, 2^{size}] @f$ + * I | Signed Integer @f$ [-2^{size-1}, 2^{size-1}-1] @f$ + * F | Floating-point + * + * + * Special color formats + * --------------------- + * + * There are a few special color formats that don't follow the convention above: + * + * Name | Format + * :----------------|:-------------------------------------------------------------------------- + * RGB565 | 5-bits for R and B, 6-bits for G. + * RGB5_A1 | 5-bits for R, G and B, 1-bit for A. + * RGB10_A2 | 10-bits for R, G and B, 2-bits for A. + * RGB9_E5 | **Unsigned** floating point. 9-bits mantissa for RGB, 5-bits shared exponent + * R11F_G11F_B10F | **Unsigned** floating point. 6-bits mantissa, for R and G, 5-bits for B. 5-bits exponent. + * SRGB8_A8 | sRGB 8-bits with linear 8-bits alpha. + * DEPTH24_STENCIL8 | 24-bits unsigned normalized integer depth, 8-bits stencil. + * DEPTH32F_STENCIL8| 32-bits floating-point depth, 8-bits stencil. + * + * + * Compressed texture formats + * -------------------------- + * + * Many compressed texture formats are supported as well, which include (but are not limited to) + * the following list: + * + * Name | Format + * :----------------|:-------------------------------------------------------------------------- + * EAC_R11 | Compresses R11UI + * EAC_R11_SIGNED | Compresses R11I + * EAC_RG11 | Compresses RG11UI + * EAC_RG11_SIGNED | Compresses RG11I + * ETC2_RGB8 | Compresses RGB8 + * ETC2_SRGB8 | compresses SRGB8 + * ETC2_EAC_RGBA8 | Compresses RGBA8 + * ETC2_EAC_SRGBA8 | Compresses SRGB8_A8 + * ETC2_RGB8_A1 | Compresses RGB8 with 1-bit alpha + * ETC2_SRGB8_A1 | Compresses sRGB8 with 1-bit alpha + * + * + * @see Texture + */ +enum class TextureFormat : uint16_t { + // 8-bits per element + R8, R8_SNORM, R8UI, R8I, STENCIL8, + + // 16-bits per element + R16F, R16UI, R16I, + RG8, RG8_SNORM, RG8UI, RG8I, + RGB565, + RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons. + RGB5_A1, + RGBA4, + DEPTH16, + + // 24-bits per element + RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, + DEPTH24, + + // 32-bits per element + R32F, R32UI, R32I, + RG16F, RG16UI, RG16I, + R11F_G11F_B10F, + RGBA8, SRGB8_A8,RGBA8_SNORM, + UNUSED, // used to be rgbm + RGB10_A2, RGBA8UI, RGBA8I, + DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8, + + // 48-bits per element + RGB16F, RGB16UI, RGB16I, + + // 64-bits per element + RG32F, RG32UI, RG32I, + RGBA16F, RGBA16UI, RGBA16I, + + // 96-bits per element + RGB32F, RGB32UI, RGB32I, + + // 128-bits per element + RGBA32F, RGBA32UI, RGBA32I, + + // compressed formats + + // Mandatory in GLES 3.0 and GL 4.3 + EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, + ETC2_RGB8, ETC2_SRGB8, + ETC2_RGB8_A1, ETC2_SRGB8_A1, + ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, + + // Available everywhere except Android/iOS + DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, + DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, + + // ASTC formats are available with a GLES extension + RGBA_ASTC_4x4, + RGBA_ASTC_5x4, + RGBA_ASTC_5x5, + RGBA_ASTC_6x5, + RGBA_ASTC_6x6, + RGBA_ASTC_8x5, + RGBA_ASTC_8x6, + RGBA_ASTC_8x8, + RGBA_ASTC_10x5, + RGBA_ASTC_10x6, + RGBA_ASTC_10x8, + RGBA_ASTC_10x10, + RGBA_ASTC_12x10, + RGBA_ASTC_12x12, + SRGB8_ALPHA8_ASTC_4x4, + SRGB8_ALPHA8_ASTC_5x4, + SRGB8_ALPHA8_ASTC_5x5, + SRGB8_ALPHA8_ASTC_6x5, + SRGB8_ALPHA8_ASTC_6x6, + SRGB8_ALPHA8_ASTC_8x5, + SRGB8_ALPHA8_ASTC_8x6, + SRGB8_ALPHA8_ASTC_8x8, + SRGB8_ALPHA8_ASTC_10x5, + SRGB8_ALPHA8_ASTC_10x6, + SRGB8_ALPHA8_ASTC_10x8, + SRGB8_ALPHA8_ASTC_10x10, + SRGB8_ALPHA8_ASTC_12x10, + SRGB8_ALPHA8_ASTC_12x12, + + // RGTC formats available with a GLES extension + RED_RGTC1, // BC4 unsigned + SIGNED_RED_RGTC1, // BC4 signed + RED_GREEN_RGTC2, // BC5 unsigned + SIGNED_RED_GREEN_RGTC2, // BC5 signed + + // BPTC formats available with a GLES extension + RGB_BPTC_SIGNED_FLOAT, // BC6H signed + RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned + RGBA_BPTC_UNORM, // BC7 + SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB +}; + +//! Bitmask describing the intended Texture Usage +enum class TextureUsage : uint8_t { + NONE = 0x00, + COLOR_ATTACHMENT = 0x01, //!< Texture can be used as a color attachment + DEPTH_ATTACHMENT = 0x02, //!< Texture can be used as a depth attachment + STENCIL_ATTACHMENT = 0x04, //!< Texture can be used as a stencil attachment + UPLOADABLE = 0x08, //!< Data can be uploaded into this texture (default) + SAMPLEABLE = 0x10, //!< Texture can be sampled (default) + SUBPASS_INPUT = 0x20, //!< Texture can be used as a subpass input + BLIT_SRC = 0x40, //!< Texture can be used the source of a blit() + BLIT_DST = 0x80, //!< Texture can be used the destination of a blit() + DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage +}; + +//! Texture swizzle +enum class TextureSwizzle : uint8_t { + SUBSTITUTE_ZERO, + SUBSTITUTE_ONE, + CHANNEL_0, + CHANNEL_1, + CHANNEL_2, + CHANNEL_3 +}; + +//! returns whether this format a depth format +static constexpr bool isDepthFormat(TextureFormat format) noexcept { + switch (format) { + case TextureFormat::DEPTH32F: + case TextureFormat::DEPTH24: + case TextureFormat::DEPTH16: + case TextureFormat::DEPTH32F_STENCIL8: + case TextureFormat::DEPTH24_STENCIL8: + return true; + default: + return false; + } +} + +static constexpr bool isStencilFormat(TextureFormat format) noexcept { + switch (format) { + case TextureFormat::STENCIL8: + case TextureFormat::DEPTH24_STENCIL8: + case TextureFormat::DEPTH32F_STENCIL8: + return true; + default: + return false; + } +} + +static constexpr bool isUnsignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8UI: + case TextureFormat::R16UI: + case TextureFormat::R32UI: + case TextureFormat::RG8UI: + case TextureFormat::RG16UI: + case TextureFormat::RG32UI: + case TextureFormat::RGB8UI: + case TextureFormat::RGB16UI: + case TextureFormat::RGB32UI: + case TextureFormat::RGBA8UI: + case TextureFormat::RGBA16UI: + case TextureFormat::RGBA32UI: + return true; + + default: + return false; + } +} + +static constexpr bool isSignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8I: + case TextureFormat::R16I: + case TextureFormat::R32I: + case TextureFormat::RG8I: + case TextureFormat::RG16I: + case TextureFormat::RG32I: + case TextureFormat::RGB8I: + case TextureFormat::RGB16I: + case TextureFormat::RGB32I: + case TextureFormat::RGBA8I: + case TextureFormat::RGBA16I: + case TextureFormat::RGBA32I: + return true; + + default: + return false; + } +} + +//! returns whether this format is a compressed format +static constexpr bool isCompressedFormat(TextureFormat format) noexcept { + return format >= TextureFormat::EAC_R11; +} + +//! returns whether this format is an ETC2 compressed format +static constexpr bool isETC2Compression(TextureFormat format) noexcept { + return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8; +} + +//! returns whether this format is an S3TC compressed format +static constexpr bool isS3TCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA; +} + +static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept { + return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA; +} + +//! returns whether this format is an RGTC compressed format +static constexpr bool isRGTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2; +} + +//! returns whether this format is an BPTC compressed format +static constexpr bool isBPTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM; +} + +static constexpr bool isASTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12; +} + +//! Texture Cubemap Face +enum class TextureCubemapFace : uint8_t { + // don't change the enums values + POSITIVE_X = 0, //!< +x face + NEGATIVE_X = 1, //!< -x face + POSITIVE_Y = 2, //!< +y face + NEGATIVE_Y = 3, //!< -y face + POSITIVE_Z = 4, //!< +z face + NEGATIVE_Z = 5, //!< -z face +}; + +//! Sampler Wrap mode +enum class SamplerWrapMode : uint8_t { + CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity. + REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction. + MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction. +}; + +//! Sampler minification filter +enum class SamplerMinFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. + NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs. + LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level. + NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs. + LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used. +}; + +//! Sampler magnification filter +enum class SamplerMagFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. +}; + +//! Sampler compare mode +enum class SamplerCompareMode : uint8_t { + // don't change the enums values + NONE = 0, + COMPARE_TO_TEXTURE = 1 +}; + +//! comparison function for the depth / stencil sampler +enum class SamplerCompareFunc : uint8_t { + // don't change the enums values + LE = 0, //!< Less or equal + GE, //!< Greater or equal + L, //!< Strictly less than + G, //!< Strictly greater than + E, //!< Equal + NE, //!< Not equal + A, //!< Always. Depth / stencil testing is deactivated. + N //!< Never. The depth / stencil test always fails. +}; + +//! Sampler parameters +struct SamplerParams { // NOLINT + SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST) + SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST) + SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE) + SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE) + + SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE) + uint8_t anisotropyLog2 : 3; //!< anisotropy level (0) + SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE) + uint8_t padding0 : 2; //!< reserved. must be 0. + + SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE) + uint8_t padding1 : 5; //!< reserved. must be 0. + uint8_t padding2 : 8; //!< reserved. must be 0. + + struct Hasher { + size_t operator()(SamplerParams p) const noexcept { + // we don't use std::hash<> here, so we don't have to include + return *reinterpret_cast(reinterpret_cast(&p)); + } + }; + + struct EqualTo { + bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + + struct LessThan { + bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + +private: + friend inline bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept { + return SamplerParams::LessThan{}(lhs, rhs); + } +}; +static_assert(sizeof(SamplerParams) == 4); + +// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code +// see android/.../TextureSampler.cpp +static_assert(sizeof(SamplerParams) <= sizeof(uint64_t), + "SamplerParams must be no more than 64 bits"); + +//! blending equation function +enum class BlendEquation : uint8_t { + ADD, //!< the fragment is added to the color buffer + SUBTRACT, //!< the fragment is subtracted from the color buffer + REVERSE_SUBTRACT, //!< the color buffer is subtracted from the fragment + MIN, //!< the min between the fragment and color buffer + MAX //!< the max between the fragment and color buffer +}; + +//! blending function +enum class BlendFunction : uint8_t { + ZERO, //!< f(src, dst) = 0 + ONE, //!< f(src, dst) = 1 + SRC_COLOR, //!< f(src, dst) = src + ONE_MINUS_SRC_COLOR, //!< f(src, dst) = 1-src + DST_COLOR, //!< f(src, dst) = dst + ONE_MINUS_DST_COLOR, //!< f(src, dst) = 1-dst + SRC_ALPHA, //!< f(src, dst) = src.a + ONE_MINUS_SRC_ALPHA, //!< f(src, dst) = 1-src.a + DST_ALPHA, //!< f(src, dst) = dst.a + ONE_MINUS_DST_ALPHA, //!< f(src, dst) = 1-dst.a + SRC_ALPHA_SATURATE //!< f(src, dst) = (1,1,1) * min(src.a, 1 - dst.a), 1 +}; + +//! stencil operation +enum class StencilOperation : uint8_t { + KEEP, //!< Keeps the current value. + ZERO, //!< Sets the value to 0. + REPLACE, //!< Sets the value to the stencil reference value. + INCR, //!< Increments the current value. Clamps to the maximum representable unsigned value. + INCR_WRAP, //!< Increments the current value. Wraps value to zero when incrementing the maximum representable unsigned value. + DECR, //!< Decrements the current value. Clamps to 0. + DECR_WRAP, //!< Decrements the current value. Wraps value to the maximum representable unsigned value when decrementing a value of zero. + INVERT, //!< Bitwise inverts the current value. +}; + +//! stencil faces +enum class StencilFace : uint8_t { + FRONT = 0x1, //!< Update stencil state for front-facing polygons. + BACK = 0x2, //!< Update stencil state for back-facing polygons. + FRONT_AND_BACK = FRONT | BACK, //!< Update stencil state for all polygons. +}; + +//! Stream for external textures +enum class StreamType { + NATIVE, //!< Not synchronized but copy-free. Good for video. + ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+. +}; + +//! Releases an ACQUIRED external texture, guaranteed to be called on the application thread. +using StreamCallback = void(*)(void* image, void* user); + +//! Vertex attribute descriptor +struct Attribute { + //! attribute is normalized (remapped between 0 and 1) + static constexpr uint8_t FLAG_NORMALIZED = 0x1; + //! attribute is an integer + static constexpr uint8_t FLAG_INTEGER_TARGET = 0x2; + static constexpr uint8_t BUFFER_UNUSED = 0xFF; + uint32_t offset = 0; //!< attribute offset in bytes + uint8_t stride = 0; //!< attribute stride in bytes + uint8_t buffer = BUFFER_UNUSED; //!< attribute buffer index + ElementType type = ElementType::BYTE; //!< attribute element type + uint8_t flags = 0x0; //!< attribute flags +}; + +using AttributeArray = std::array; + +//! Raster state descriptor +struct RasterState { + + using CullingMode = backend::CullingMode; + using DepthFunc = backend::SamplerCompareFunc; + using BlendEquation = backend::BlendEquation; + using BlendFunction = backend::BlendFunction; + + RasterState() noexcept { // NOLINT + static_assert(sizeof(RasterState) == sizeof(uint32_t), + "RasterState size not what was intended"); + culling = CullingMode::BACK; + blendEquationRGB = BlendEquation::ADD; + blendEquationAlpha = BlendEquation::ADD; + blendFunctionSrcRGB = BlendFunction::ONE; + blendFunctionSrcAlpha = BlendFunction::ONE; + blendFunctionDstRGB = BlendFunction::ZERO; + blendFunctionDstAlpha = BlendFunction::ZERO; + } + + bool operator == (RasterState rhs) const noexcept { return u == rhs.u; } + bool operator != (RasterState rhs) const noexcept { return u != rhs.u; } + + void disableBlending() noexcept { + blendEquationRGB = BlendEquation::ADD; + blendEquationAlpha = BlendEquation::ADD; + blendFunctionSrcRGB = BlendFunction::ONE; + blendFunctionSrcAlpha = BlendFunction::ONE; + blendFunctionDstRGB = BlendFunction::ZERO; + blendFunctionDstAlpha = BlendFunction::ZERO; + } + + // note: clang reduces this entire function to a simple load/mask/compare + bool hasBlending() const noexcept { + // This is used to decide if blending needs to be enabled in the h/w + return !(blendEquationRGB == BlendEquation::ADD && + blendEquationAlpha == BlendEquation::ADD && + blendFunctionSrcRGB == BlendFunction::ONE && + blendFunctionSrcAlpha == BlendFunction::ONE && + blendFunctionDstRGB == BlendFunction::ZERO && + blendFunctionDstAlpha == BlendFunction::ZERO); + } + + union { + struct { + //! culling mode + CullingMode culling : 2; // 2 + + //! blend equation for the red, green and blue components + BlendEquation blendEquationRGB : 3; // 5 + //! blend equation for the alpha component + BlendEquation blendEquationAlpha : 3; // 8 + + //! blending function for the source color + BlendFunction blendFunctionSrcRGB : 4; // 12 + //! blending function for the source alpha + BlendFunction blendFunctionSrcAlpha : 4; // 16 + //! blending function for the destination color + BlendFunction blendFunctionDstRGB : 4; // 20 + //! blending function for the destination alpha + BlendFunction blendFunctionDstAlpha : 4; // 24 + + //! Whether depth-buffer writes are enabled + bool depthWrite : 1; // 25 + //! Depth test function + DepthFunc depthFunc : 3; // 28 + + //! Whether color-buffer writes are enabled + bool colorWrite : 1; // 29 + + //! use alpha-channel as coverage mask for anti-aliasing + bool alphaToCoverage : 1; // 30 + + //! whether front face winding direction must be inverted + bool inverseFrontFaces : 1; // 31 + + //! padding, must be 0 + uint8_t padding : 1; // 32 + }; + uint32_t u = 0; + }; +}; + +/** + ********************************************************************************************** + * \privatesection + */ + +enum class ShaderStage : uint8_t { + VERTEX = 0, + FRAGMENT = 1, + COMPUTE = 2 +}; + +static constexpr size_t PIPELINE_STAGE_COUNT = 2; +enum class ShaderStageFlags : uint8_t { + NONE = 0, + VERTEX = 0x1, + FRAGMENT = 0x2, + COMPUTE = 0x4, + ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE +}; + +static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept { + switch (type) { + case ShaderStage::VERTEX: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX)); + case ShaderStage::FRAGMENT: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::FRAGMENT)); + case ShaderStage::COMPUTE: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::COMPUTE)); + } +} + +/** + * Selects which buffers to clear at the beginning of the render pass, as well as which buffers + * can be discarded at the beginning and end of the render pass. + * + */ +struct RenderPassFlags { + /** + * bitmask indicating which buffers to clear at the beginning of a render pass. + * This implies discard. + */ + TargetBufferFlags clear; + + /** + * bitmask indicating which buffers to discard at the beginning of a render pass. + * Discarded buffers have uninitialized content, they must be entirely drawn over or cleared. + */ + TargetBufferFlags discardStart; + + /** + * bitmask indicating which buffers to discard at the end of a render pass. + * Discarded buffers' content becomes invalid, they must not be read from again. + */ + TargetBufferFlags discardEnd; +}; + +/** + * Parameters of a render pass. + */ +struct RenderPassParams { + RenderPassFlags flags{}; //!< operations performed on the buffers for this pass + + Viewport viewport{}; //!< viewport for this pass + DepthRange depthRange{}; //!< depth range for this pass + + //! Color to use to clear the COLOR buffer. RenderPassFlags::clear must be set. + math::float4 clearColor = {}; + + //! Depth value to clear the depth buffer with + double clearDepth = 0.0; + + //! Stencil value to clear the stencil buffer with + uint32_t clearStencil = 0; + + /** + * The subpass mask specifies which color attachments are designated for read-back in the second + * subpass. If this is zero, the render pass has only one subpass. The least significant bit + * specifies that the first color attachment in the render target is a subpass input. + * + * For now only 2 subpasses are supported, so only the lower 8 bits are used, one for each color + * attachment (see MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT). + */ + uint16_t subpassMask = 0; + + /** + * This mask makes a promise to the backend about read-only usage of the depth attachment (bit + * 0) and the stencil attachment (bit 1). Some backends need to know if writes are disabled in + * order to allow sampling from the depth attachment. + */ + uint16_t readOnlyDepthStencil = 0; + + static constexpr uint16_t READONLY_DEPTH = 1 << 0; + static constexpr uint16_t READONLY_STENCIL = 1 << 1; +}; + +struct PolygonOffset { + float slope = 0; // factor in GL-speak + float constant = 0; // units in GL-speak +}; + +struct StencilState { + using StencilFunction = SamplerCompareFunc; + + struct StencilOperations { + //! Stencil test function + StencilFunction stencilFunc : 3; // 3 + + //! Stencil operation when stencil test fails + StencilOperation stencilOpStencilFail : 3; // 6 + + uint8_t padding0 : 2; // 8 + + //! Stencil operation when stencil test passes but depth test fails + StencilOperation stencilOpDepthFail : 3; // 11 + + //! Stencil operation when both stencil and depth test pass + StencilOperation stencilOpDepthStencilPass : 3; // 14 + + uint8_t padding1 : 2; // 16 + + //! Reference value for stencil comparison tests and updates + uint8_t ref; // 24 + + //! Masks the bits of the stencil values participating in the stencil comparison test. + uint8_t readMask; // 32 + + //! Masks the bits of the stencil values updated by the stencil test. + uint8_t writeMask; // 40 + }; + + //! Stencil operations for front-facing polygons + StencilOperations front = { + .stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff }; + + //! Stencil operations for back-facing polygons + StencilOperations back = { + .stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff }; + + //! Whether stencil-buffer writes are enabled + bool stencilWrite = false; + + uint8_t padding = 0; +}; + +static_assert(sizeof(StencilState::StencilOperations) == 5u, + "StencilOperations size not what was intended"); + +static_assert(sizeof(StencilState) == 12u, + "StencilState size not what was intended"); + +using FrameScheduledCallback = void(*)(PresentCallable callable, void* user); + +enum class Workaround : uint16_t { + // The EASU pass must split because shader compiler flattens early-exit branch + SPLIT_EASU, + // Backend allows feedback loop with ancillary buffers (depth/stencil) as long as they're + // read-only for the whole render pass. + ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP, + // for some uniform arrays, it's needed to do an initialization to avoid crash on adreno gpu + ADRENO_UNIFORM_ARRAY_CRASH, + // Workaround a Metal pipeline compilation error with the message: + // "Could not statically determine the target of a texture". See light_indirect.fs + A8X_STATIC_TEXTURE_TARGET_ERROR, + // Adreno drivers sometimes aren't able to blit into a layer of a texture array. + DISABLE_BLIT_INTO_TEXTURE_ARRAY, + // Multiple workarounds needed for PowerVR GPUs + POWER_VR_SHADER_WORKAROUNDS, + // The driver has some threads pinned, and we can't easily know on which core, it can hurt + // performance more if we end-up pinned on the same one. + DISABLE_THREAD_AFFINITY +}; + +//! The type of technique for stereoscopic rendering +enum class StereoscopicType : uint8_t { + // Stereoscopic rendering is performed using instanced rendering technique. + INSTANCED, + // Stereoscopic rendering is performed using the multiview feature from the graphics backend. + MULTIVIEW, +}; + +} // namespace filament::backend + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableIntegerOperators + : public std::true_type {}; +template<> struct utils::EnableIntegerOperators + : public std::true_type {}; + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::CullingMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ElementType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::Precision precision); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PrimitiveType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TargetBufferFlags f); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareFunc func); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMagFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMinFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerParams params); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerWrapMode wrap); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ShaderModel model); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureCubemapFace face); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferObjectBinding binding); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureSwizzle swizzle); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::AttributeArray& type); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PolygonOffset& po); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RasterState& rs); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RenderPassParams& b); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::Viewport& v); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ShaderStageFlags stageFlags); +#endif + +#endif // TNT_FILAMENT_BACKEND_DRIVERENUMS_H diff --git a/package/android/libs/filament/include/backend/Handle.h b/package/android/libs/filament/include/backend/Handle.h new file mode 100644 index 00000000..ffc16133 --- /dev/null +++ b/package/android/libs/filament/include/backend/Handle.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_HANDLE_H +#define TNT_FILAMENT_BACKEND_HANDLE_H + +#if !defined(NDEBUG) +#include +#endif +#include + +#include // FIXME: STL headers are not allowed in public headers + +#include + +namespace filament::backend { + +struct HwBufferObject; +struct HwFence; +struct HwIndexBuffer; +struct HwProgram; +struct HwRenderPrimitive; +struct HwRenderTarget; +struct HwSamplerGroup; +struct HwStream; +struct HwSwapChain; +struct HwTexture; +struct HwTimerQuery; +struct HwVertexBuffer; + +/* + * A handle to a backend resource. HandleBase is for internal use only. + * HandleBase *must* be a trivial for the purposes of calls, that is, it cannot have user-defined + * copy or move constructors. + */ + +//! \privatesection + +class HandleBase { +public: + using HandleId = uint32_t; + static constexpr const HandleId nullid = HandleId{ UINT32_MAX }; + + constexpr HandleBase() noexcept: object(nullid) {} + + // whether this Handle is initialized + explicit operator bool() const noexcept { return object != nullid; } + + // clear the handle, this doesn't free associated resources + void clear() noexcept { object = nullid; } + + // get this handle's handleId + HandleId getId() const noexcept { return object; } + + // initialize a handle, for internal use only. + explicit HandleBase(HandleId id) noexcept : object(id) { + assert_invariant(object != nullid); // usually means an uninitialized handle is used + } + +protected: + HandleBase(HandleBase const& rhs) noexcept = default; + HandleBase& operator=(HandleBase const& rhs) noexcept = default; + +private: + HandleId object; +}; + +/** + * Type-safe handle to backend resources + * @tparam T Type of the resource + */ +template +struct Handle : public HandleBase { + + Handle() noexcept = default; + + Handle(Handle const& rhs) noexcept = default; + + Handle& operator=(Handle const& rhs) noexcept = default; + + explicit Handle(HandleId id) noexcept : HandleBase(id) { } + + // compare handles of the same type + bool operator==(const Handle& rhs) const noexcept { return getId() == rhs.getId(); } + bool operator!=(const Handle& rhs) const noexcept { return getId() != rhs.getId(); } + bool operator<(const Handle& rhs) const noexcept { return getId() < rhs.getId(); } + bool operator<=(const Handle& rhs) const noexcept { return getId() <= rhs.getId(); } + bool operator>(const Handle& rhs) const noexcept { return getId() > rhs.getId(); } + bool operator>=(const Handle& rhs) const noexcept { return getId() >= rhs.getId(); } + + // type-safe Handle cast + template::value> > + Handle(Handle const& base) noexcept : HandleBase(base) { } // NOLINT(hicpp-explicit-conversions,google-explicit-constructor) + +private: +#if !defined(NDEBUG) + template + friend utils::io::ostream& operator<<(utils::io::ostream& out, const Handle& h) noexcept; +#endif +}; + +// Types used by the command stream +// (we use this renaming because the macro-system doesn't deal well with "<" and ">") +using BufferObjectHandle = Handle; +using FenceHandle = Handle; +using IndexBufferHandle = Handle; +using ProgramHandle = Handle; +using RenderPrimitiveHandle = Handle; +using RenderTargetHandle = Handle; +using SamplerGroupHandle = Handle; +using StreamHandle = Handle; +using SwapChainHandle = Handle; +using TextureHandle = Handle; +using TimerQueryHandle = Handle; +using VertexBufferHandle = Handle; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_HANDLE_H diff --git a/package/android/libs/filament/include/backend/PipelineState.h b/package/android/libs/filament/include/backend/PipelineState.h new file mode 100644 index 00000000..aa98dda6 --- /dev/null +++ b/package/android/libs/filament/include/backend/PipelineState.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PIPELINESTATE_H +#define TNT_FILAMENT_BACKEND_PIPELINESTATE_H + +#include +#include + +#include + +#include + +namespace filament::backend { + +//! \privatesection + +struct PipelineState { + Handle program; + RasterState rasterState; + StencilState stencilState; + PolygonOffset polygonOffset; + Viewport scissor{ 0, 0, (uint32_t)INT32_MAX, (uint32_t)INT32_MAX }; +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PipelineState& ps); +#endif + +#endif //TNT_FILAMENT_BACKEND_PIPELINESTATE_H diff --git a/package/android/libs/filament/include/backend/PixelBufferDescriptor.h b/package/android/libs/filament/include/backend/PixelBufferDescriptor.h new file mode 100644 index 00000000..c45f344d --- /dev/null +++ b/package/android/libs/filament/include/backend/PixelBufferDescriptor.h @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H + +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +/** + * A descriptor to an image in main memory, typically used to transfer image data from the CPU + * to the GPU. + * + * A PixelBufferDescriptor owns the memory buffer it references, therefore PixelBufferDescriptor + * cannot be copied, but can be moved. + * + * PixelBufferDescriptor releases ownership of the memory-buffer when it's destroyed. + */ +class UTILS_PUBLIC PixelBufferDescriptor : public BufferDescriptor { +public: + using PixelDataFormat = backend::PixelDataFormat; + using PixelDataType = backend::PixelDataType; + + PixelBufferDescriptor() = default; + + /** + * Creates a new PixelBufferDescriptor referencing an image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param alignment Alignment in bytes of pixel rows + * @param left Left coordinate in pixels + * @param top Top coordinate in pixels + * @param stride Stride of a row in pixels + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + left(left), top(top), stride(stride), + format(format), type(type), alignment(alignment) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment = 1, + uint32_t left = 0, uint32_t top = 0, uint32_t stride = 0, + Callback callback = nullptr, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + left(left), top(top), stride(stride), + format(format), type(type), alignment(alignment) { + } + + /** + * Creates a new PixelBufferDescriptor referencing an image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + stride(0), format(format), type(type), alignment(1) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, + Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + stride(0), format(format), type(type), alignment(1) { + } + + + /** + * Creates a new PixelBufferDescriptor referencing a compressed image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Compressed format of the image + * @param imageSize Compressed size of the image + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + imageSize(imageSize), compressedFormat(format), type(PixelDataType::COMPRESSED), + alignment(1) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, + Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + imageSize(imageSize), compressedFormat(format), type(PixelDataType::COMPRESSED), + alignment(1) { + } + + // -------------------------------------------------------------------------------------------- + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, imageSize, handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, imageSize, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + + /** + * Computes the size in bytes needed to fit an image of given dimensions and format + * + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param stride Stride of a row in pixels + * @param height Height of the image in rows + * @param alignment Alignment in bytes of pixel rows + * @return The buffer size needed to fit this image in bytes + */ + static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type, + size_t stride, size_t height, size_t alignment) noexcept { + assert_invariant(alignment); + + if (type == PixelDataType::COMPRESSED) { + return 0; + } + + size_t n = 0; + switch (format) { + case PixelDataFormat::R: + case PixelDataFormat::R_INTEGER: + case PixelDataFormat::DEPTH_COMPONENT: + case PixelDataFormat::ALPHA: + n = 1; + break; + case PixelDataFormat::RG: + case PixelDataFormat::RG_INTEGER: + case PixelDataFormat::DEPTH_STENCIL: + n = 2; + break; + case PixelDataFormat::RGB: + case PixelDataFormat::RGB_INTEGER: + n = 3; + break; + case PixelDataFormat::UNUSED: // shouldn't happen (used to be rgbm) + case PixelDataFormat::RGBA: + case PixelDataFormat::RGBA_INTEGER: + n = 4; + break; + } + + size_t bpp = n; + switch (type) { + case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings + case PixelDataType::UBYTE: + case PixelDataType::BYTE: + // nothing to do + break; + case PixelDataType::USHORT: + case PixelDataType::SHORT: + case PixelDataType::HALF: + bpp *= 2; + break; + case PixelDataType::UINT: + case PixelDataType::INT: + case PixelDataType::FLOAT: + bpp *= 4; + break; + case PixelDataType::UINT_10F_11F_11F_REV: + // Special case, format must be RGB and uses 4 bytes + assert_invariant(format == PixelDataFormat::RGB); + bpp = 4; + break; + case PixelDataType::UINT_2_10_10_10_REV: + // Special case, format must be RGBA and uses 4 bytes + assert_invariant(format == PixelDataFormat::RGBA); + bpp = 4; + break; + case PixelDataType::USHORT_565: + // Special case, format must be RGB and uses 2 bytes + assert_invariant(format == PixelDataFormat::RGB); + bpp = 2; + break; + } + + size_t const bpr = bpp * stride; + size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1); + return bprAligned * height; + } + + //! left coordinate in pixels + uint32_t left = 0; + //! top coordinate in pixels + uint32_t top = 0; + union { + struct { + //! stride in pixels + uint32_t stride; + //! Pixel data format + PixelDataFormat format; + }; + struct { + //! compressed image size + uint32_t imageSize; + //! compressed image format + backend::CompressedPixelDataType compressedFormat; + }; + }; + //! pixel data type + PixelDataType type : 4; + //! row alignment in bytes + uint8_t alignment : 4; +}; + +} // namespace backend::filament + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PixelBufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H diff --git a/package/android/libs/filament/include/backend/Platform.h b/package/android/libs/filament/include/backend/Platform.h new file mode 100644 index 00000000..b89fb98f --- /dev/null +++ b/package/android/libs/filament/include/backend/Platform.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PLATFORM_H +#define TNT_FILAMENT_BACKEND_PLATFORM_H + +#include +#include + +#include + +namespace filament::backend { + +class Driver; + +/** + * Platform is an interface that abstracts how the backend (also referred to as Driver) is + * created. The backend provides several common Platform concrete implementations, which are + * selected automatically. It is possible however to provide a custom Platform when creating + * the filament Engine. + */ +class UTILS_PUBLIC Platform { +public: + struct SwapChain {}; + struct Fence {}; + struct Stream {}; + + struct DriverConfig { + /** + * Size of handle arena in bytes. Setting to 0 indicates default value is to be used. + * Driver clamps to valid values. + */ + size_t handleArenaSize = 0; + + /** + * This number of most-recently destroyed textures will be tracked for use-after-free. + * Throws an exception when a texture is freed but still bound to a SamplerGroup and used in + * a draw call. 0 disables completely. Currently only respected by the Metal backend. + */ + size_t textureUseAfterFreePoolSize = 0; + + /** + * Set to `true` to forcibly disable parallel shader compilation in the backend. + * Currently only honored by the GL backend. + */ + bool disableParallelShaderCompile = false; + }; + + Platform() noexcept; + + virtual ~Platform() noexcept; + + /** + * Queries the underlying OS version. + * @return The OS version. + */ + virtual int getOSVersion() const noexcept = 0; + + /** + * Creates and initializes the low-level API (e.g. an OpenGL context or Vulkan instance), + * then creates the concrete Driver. + * The caller takes ownership of the returned Driver* and must destroy it with delete. + * + * @param sharedContext an optional shared context. This is not meaningful with all graphic + * APIs and platforms. + * For EGL platforms, this is an EGLContext. + * + * @param driverConfig specifies driver initialization parameters + * + * @return nullptr on failure, or a pointer to the newly created driver. + */ + virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, + const DriverConfig& driverConfig) noexcept = 0; + + /** + * Processes the platform's event queue when called from its primary event-handling thread. + * + * Internally, Filament might need to call this when waiting on a fence. It is only implemented + * on platforms that need it, such as macOS + OpenGL. Returns false if this is not the main + * thread, or if the platform does not need to perform any special processing. + */ + virtual bool pumpEvents() noexcept; + + /** + * InsertBlobFunc is an Invocable to an application-provided function that a + * backend implementation may use to insert a key/value pair into the + * cache. + */ + using InsertBlobFunc = utils::Invocable< + void(const void* UTILS_NONNULL key, size_t keySize, + const void* UTILS_NONNULL value, size_t valueSize)>; + + /* + * RetrieveBlobFunc is an Invocable to an application-provided function that a + * backend implementation may use to retrieve a cached value from the + * cache. + */ + using RetrieveBlobFunc = utils::Invocable< + size_t(const void* UTILS_NONNULL key, size_t keySize, + void* UTILS_NONNULL value, size_t valueSize)>; + + /** + * Sets the callback functions that the backend can use to interact with caching functionality + * provided by the application. + * + * Cache functions may only be specified once during the lifetime of a + * Platform. The and Invocables may be called at any time and + * from any thread from the time at which setBlobFunc is called until the time that Platform + * is destroyed. Concurrent calls to these functions from different threads is also allowed. + * Either function can be null. + * + * @param insertBlob an Invocable that inserts a new value into the cache and associates + * it with the given key + * @param retrieveBlob an Invocable that retrieves from the cache the value associated with a + * given key + */ + void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept; + + /** + * @return true if insertBlob is valid. + */ + bool hasInsertBlobFunc() const noexcept; + + /** + * @return true if retrieveBlob is valid. + */ + bool hasRetrieveBlobFunc() const noexcept; + + /** + * @return true if either of insertBlob or retrieveBlob are valid. + */ + bool hasBlobFunc() const noexcept { + return hasInsertBlobFunc() || hasRetrieveBlobFunc(); + } + + /** + * To insert a new binary value into the cache and associate it with a given + * key, the backend implementation can call the application-provided callback + * function insertBlob. + * + * No guarantees are made as to whether a given key/value pair is present in + * the cache after the set call. If a different value has been associated + * with the given key in the past then it is undefined which value, if any, is + * associated with the key after the set call. Note that while there are no + * guarantees, the cache implementation should attempt to cache the most + * recently set value for a given key. + * + * @param key pointer to the beginning of the key data that is to be inserted + * @param keySize specifies the size in byte of the data pointed to by + * @param value pointer to the beginning of the value data that is to be inserted + * @param valueSize specifies the size in byte of the data pointed to by + */ + void insertBlob(const void* UTILS_NONNULL key, size_t keySize, + const void* UTILS_NONNULL value, size_t valueSize); + + /** + * To retrieve the binary value associated with a given key from the cache, a + * the backend implementation can call the application-provided callback + * function retrieveBlob. + * + * If the cache contains a value for the given key and its size in bytes is + * less than or equal to then the value is written to the memory + * pointed to by . Otherwise nothing is written to the memory pointed + * to by . + * + * @param key pointer to the beginning of the key + * @param keySize specifies the size in bytes of the binary key pointed to by + * @param value pointer to a buffer to receive the cached binary data, if it exists + * @param valueSize specifies the size in bytes of the memory pointed to by + * @return If the cache contains a value associated with the given key then the + * size of that binary value in bytes is returned. Otherwise 0 is returned. + */ + size_t retrieveBlob(const void* UTILS_NONNULL key, size_t keySize, + void* UTILS_NONNULL value, size_t valueSize); + +private: + InsertBlobFunc mInsertBlob; + RetrieveBlobFunc mRetrieveBlob; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BACKEND_PLATFORM_H diff --git a/package/android/libs/filament/include/backend/PresentCallable.h b/package/android/libs/filament/include/backend/PresentCallable.h new file mode 100644 index 00000000..4402f222 --- /dev/null +++ b/package/android/libs/filament/include/backend/PresentCallable.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PRESENTCALLABLE +#define TNT_FILAMENT_BACKEND_PRESENTCALLABLE + +#include + +namespace filament::backend { + +/** + * A PresentCallable is a callable object that, when called, schedules a frame for presentation on + * a SwapChain. + * + * Typically, Filament's backend is responsible scheduling a frame's presentation. However, there + * are certain cases where the application might want to control when a frame is scheduled for + * presentation. + * + * For example, on iOS, UIKit elements can be synchronized to 3D content by scheduling a present + * within a CATransation: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void myFrameScheduledCallback(PresentCallable presentCallable, void* user) { + * [CATransaction begin]; + * // Update other UI elements... + * presentCallable(); + * [CATransaction commit]; + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To obtain a PresentCallable, set a SwapChain::FrameScheduledCallback on a SwapChain with the + * SwapChain::setFrameScheduledCallback method. The callback is called with a PresentCallable object + * and optional user data: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * swapChain->setFrameScheduledCallback(myFrameScheduledCallback, nullptr); + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other + * backends ignore the callback (which will never be called) and proceed normally. + * + * @remark The SwapChain::FrameScheduledCallback is called on an arbitrary thread. + * + * Applications *must* call each PresentCallable they receive. Each PresentCallable represents a + * frame that is waiting to be presented. If an application fails to call a PresentCallable, a + * memory leak could occur. To "cancel" the presentation of a frame, pass false to the + * PresentCallable, which will cancel the presentation of the frame and release associated memory. + * + * @see Renderer, SwapChain::setFrameScheduledCallback + */ +class UTILS_PUBLIC PresentCallable { +public: + + using PresentFn = void(*)(bool presentFrame, void* user); + + PresentCallable(PresentFn fn, void* user) noexcept; + ~PresentCallable() noexcept = default; + PresentCallable(const PresentCallable& rhs) = default; + PresentCallable& operator=(const PresentCallable& rhs) = default; + + /** + * Call this PresentCallable, scheduling the associated frame for presentation. Pass false for + * presentFrame to effectively "cancel" the presentation of the frame. + * + * @param presentFrame if false, will not present the frame but releases associated memory + */ + void operator()(bool presentFrame = true) noexcept; + +private: + + PresentFn mPresentFn; + void* mUser = nullptr; + +}; + +/** + * @deprecated, FrameFinishedCallback has been renamed to SwapChain::FrameScheduledCallback. + */ +using FrameFinishedCallback UTILS_DEPRECATED = void(*)(PresentCallable callable, void* user); + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRESENTCALLABLE diff --git a/package/android/libs/filament/include/backend/Program.h b/package/android/libs/filament/include/backend/Program.h new file mode 100644 index 00000000..97deb6c5 --- /dev/null +++ b/package/android/libs/filament/include/backend/Program.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H +#define TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H + +#include +#include +#include +#include + +#include + +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers + +#include +#include + +namespace filament::backend { + +class Program { +public: + + static constexpr size_t SHADER_TYPE_COUNT = 3; + static constexpr size_t UNIFORM_BINDING_COUNT = CONFIG_UNIFORM_BINDING_COUNT; + static constexpr size_t SAMPLER_BINDING_COUNT = CONFIG_SAMPLER_BINDING_COUNT; + + struct Sampler { + utils::CString name = {}; // name of the sampler in the shader + uint32_t binding = 0; // binding point of the sampler in the shader + }; + + struct SamplerGroupData { + utils::FixedCapacityVector samplers; + ShaderStageFlags stageFlags = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS; + }; + + struct Uniform { + utils::CString name; // full qualified name of the uniform field + uint16_t offset; // offset in 'uint32_t' into the uniform buffer + uint8_t size; // >1 for arrays + UniformType type; // uniform type + }; + + using UniformBlockInfo = std::array; + using UniformInfo = utils::FixedCapacityVector; + using SamplerGroupInfo = std::array; + using ShaderBlob = utils::FixedCapacityVector; + using ShaderSource = std::array; + + Program() noexcept; + + Program(const Program& rhs) = delete; + Program& operator=(const Program& rhs) = delete; + + Program(Program&& rhs) noexcept; + Program& operator=(Program&& rhs) noexcept = delete; + + ~Program() noexcept; + + Program& priorityQueue(CompilerPriorityQueue priorityQueue) noexcept; + + // sets the material name and variant for diagnostic purposes only + Program& diagnostics(utils::CString const& name, + utils::Invocable&& 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(ShaderStage shader, void const* data, size_t size); + + // Note: This is only needed for GLES3.0 backends, because the layout(binding=) syntax is + // not permitted in glsl. The backend needs a way to associate a uniform block + // to a binding point. + Program& uniformBlockBindings( + utils::FixedCapacityVector> const& uniformBlockBindings) noexcept; + + // Note: This is only needed for GLES2.0, this is used to emulate UBO. This function tells + // the program everything it needs to know about the uniforms at a given binding + Program& uniforms(uint32_t index, UniformInfo const& uniforms) noexcept; + + // Note: This is only needed for GLES2.0. + Program& attributes( + utils::FixedCapacityVector> attributes) noexcept; + + // sets the 'bindingPoint' sampler group descriptor for this program. + // 'samplers' can be destroyed after this call. + // This effectively associates a set of (BindingPoints, index) to a texture unit in the shader. + // Or more precisely, what layout(binding=) is set to in GLSL. + Program& setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFlags, + Sampler const* samplers, size_t count) noexcept; + + struct SpecializationConstant { + using Type = std::variant; + uint32_t id; // id set in glsl + Type value; // value and type + }; + + Program& specializationConstants( + utils::FixedCapacityVector specConstants) noexcept; + + Program& cacheId(uint64_t cacheId) noexcept; + + ShaderSource const& getShadersSource() const noexcept { return mShadersSource; } + ShaderSource& getShadersSource() noexcept { return mShadersSource; } + + UniformBlockInfo const& getUniformBlockBindings() const noexcept { return mUniformBlocks; } + UniformBlockInfo& getUniformBlockBindings() noexcept { return mUniformBlocks; } + + SamplerGroupInfo const& getSamplerGroupInfo() const { return mSamplerGroups; } + SamplerGroupInfo& getSamplerGroupInfo() { return mSamplerGroups; } + + auto const& getBindingUniformInfo() const { return mBindingUniformInfo; } + auto& getBindingUniformInfo() { return mBindingUniformInfo; } + + auto const& getAttributes() const { return mAttributes; } + auto& getAttributes() { return mAttributes; } + + utils::CString const& getName() const noexcept { return mName; } + utils::CString& getName() noexcept { return mName; } + + utils::FixedCapacityVector const& getSpecializationConstants() const noexcept { + return mSpecializationConstants; + } + utils::FixedCapacityVector& getSpecializationConstants() noexcept { + return mSpecializationConstants; + } + + uint64_t getCacheId() const noexcept { return mCacheId; } + + CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; } + +private: + friend utils::io::ostream& operator<<(utils::io::ostream& out, const Program& builder); + + UniformBlockInfo mUniformBlocks = {}; + SamplerGroupInfo mSamplerGroups = {}; + ShaderSource mShadersSource; + utils::CString mName; + uint64_t mCacheId{}; + utils::Invocable mLogger; + utils::FixedCapacityVector mSpecializationConstants; + utils::FixedCapacityVector> mAttributes; + std::array mBindingUniformInfo; + CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H diff --git a/package/android/libs/filament/include/backend/README.md b/package/android/libs/filament/include/backend/README.md new file mode 100644 index 00000000..02268268 --- /dev/null +++ b/package/android/libs/filament/include/backend/README.md @@ -0,0 +1,4 @@ +# include/backend Headers + +Headers in `include/backend/` are fully public, in particular they can be included in filament's +public headers. diff --git a/package/android/libs/filament/include/backend/SamplerDescriptor.h b/package/android/libs/filament/include/backend/SamplerDescriptor.h new file mode 100644 index 00000000..f99472da --- /dev/null +++ b/package/android/libs/filament/include/backend/SamplerDescriptor.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H + +#include +#include + +#include + +namespace filament::backend { + +struct UTILS_PUBLIC SamplerDescriptor { + Handle t; + SamplerParams s{}; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H diff --git a/package/android/libs/filament/include/backend/TargetBufferInfo.h b/package/android/libs/filament/include/backend/TargetBufferInfo.h new file mode 100644 index 00000000..0f318d6e --- /dev/null +++ b/package/android/libs/filament/include/backend/TargetBufferInfo.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H +#define TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H + +#include + +#include + +#include +#include + +namespace filament::backend { + +//! \privatesection + +struct TargetBufferInfo { + // texture to be used as render target + Handle handle; + + // level to be used + uint8_t level = 0; + + // for cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping + uint16_t layer = 0; +}; + +class MRT { +public: + static constexpr uint8_t MIN_SUPPORTED_RENDER_TARGET_COUNT = 4u; + + // When updating this, make sure to also take care of RenderTarget.java + static constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u; + +private: + TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT]; + +public: + TargetBufferInfo const& operator[](size_t i) const noexcept { + return mInfos[i]; + } + + TargetBufferInfo& operator[](size_t i) noexcept { + return mInfos[i]; + } + + MRT() noexcept = default; + + MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions) + : mInfos{ color } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1) noexcept + : mInfos{ color0, color1 } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1, + TargetBufferInfo const& color2) noexcept + : mInfos{ color0, color1, color2 } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1, + TargetBufferInfo const& color2, TargetBufferInfo const& color3) noexcept + : mInfos{ color0, color1, color2, color3 } { + } + + // this is here for backward compatibility + MRT(Handle handle, uint8_t level, uint16_t layer) noexcept + : mInfos{{ handle, level, layer }} { + } +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::TargetBufferInfo& tbi); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::MRT& mrt); +#endif + +#endif //TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H diff --git a/package/android/libs/filament/include/backend/platforms/OpenGLPlatform.h b/package/android/libs/filament/include/backend/platforms/OpenGLPlatform.h new file mode 100644 index 00000000..12deb801 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/OpenGLPlatform.h @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H +#define TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H + +#include +#include +#include + +#include + +#include + +namespace filament::backend { + +class Driver; + +/** + * A Platform interface that creates an OpenGL backend. + * + * WARNING: None of the methods below are allowed to change the GL state and must restore it + * upon return. + * + */ +class OpenGLPlatform : public Platform { +protected: + + /* + * Derived classes can use this to instantiate the default OpenGLDriver backend. + * This is typically called from your implementation of createDriver() + */ + static Driver* UTILS_NULLABLE createDefaultDriver(OpenGLPlatform* UTILS_NONNULL platform, + void* UTILS_NULLABLE sharedContext, const DriverConfig& driverConfig); + + ~OpenGLPlatform() noexcept override; + +public: + + struct ExternalTexture { + unsigned int target; // GLenum target + unsigned int id; // GLuint id + }; + + /** + * Called by the driver to destroy the OpenGL context. This should clean up any windows + * or buffers from initialization. This is for instance where `eglDestroyContext` would be + * called. + */ + virtual void terminate() noexcept = 0; + + /** + * Called by the driver to create a SwapChain for this driver. + * + * @param nativeWindow a token representing the native window. See concrete implementation + * for details. + * @param flags extra flags used by the implementation, see filament::SwapChain + * @return The driver's SwapChain object. + * + */ + virtual SwapChain* UTILS_NONNULL createSwapChain( + void* UTILS_NULLABLE nativeWindow, uint64_t flags) noexcept = 0; + + /** + * Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag. + * The default implementation returns false. + * + * @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise. + */ + virtual bool isSRGBSwapChainSupported() const noexcept; + + /** + * Called by the driver create a headless SwapChain. + * + * @param width width of the buffer + * @param height height of the buffer + * @param flags extra flags used by the implementation, see filament::SwapChain + * @return The driver's SwapChain object. + * + * TODO: we need a more generic way of passing construction parameters + * A void* might be enough. + */ + virtual SwapChain* UTILS_NULLABLE createSwapChain( + uint32_t width, uint32_t height, uint64_t flags) noexcept = 0; + + /** + * Called by the driver to destroys the SwapChain + * @param swapChain SwapChain to be destroyed. + */ + virtual void destroySwapChain(SwapChain* UTILS_NONNULL swapChain) noexcept = 0; + + /** + * Returns the set of buffers that must be preserved up to the call to commit(). + * The default value is TargetBufferFlags::NONE. + * The color buffer is always preserved, however ancillary buffers, such as the depth buffer + * are generally discarded. The preserve flags can be used to make sure those ancillary + * buffers are preserved until the call to commit. + * + * @param swapChain + * @return buffer that must be preserved + * @see commit() + */ + virtual TargetBufferFlags getPreservedFlags(SwapChain* UTILS_NONNULL swapChain) noexcept; + + /** + * Called by the driver to establish the default FBO. The default implementation returns 0. + * @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object. + */ + virtual uint32_t createDefaultRenderTarget() noexcept; + + /** + * Called by the driver to make the OpenGL context active on the calling thread and bind + * the drawSwapChain to the default render target (FBO) created with createDefaultRenderTarget. + * @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO. + * @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`) + */ + virtual void makeCurrent( + SwapChain* UTILS_NONNULL drawSwapChain, + SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0; + + /** + * Called by the driver once the current frame finishes drawing. Typically, this should present + * the drawSwapChain. This is for example where `eglMakeCurrent()` would be called. + * @param swapChain the SwapChain to present. + */ + virtual void commit(SwapChain* UTILS_NONNULL swapChain) noexcept = 0; + + /** + * Set the time the next committed buffer should be presented to the user at. + * + * @param presentationTimeInNanosecond time in the future in nanosecond. The clock used depends + * on the concrete platform implementation. + */ + virtual void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept; + + // -------------------------------------------------------------------------------------------- + // Fence support + + /** + * Can this implementation create a Fence. + * @return true if supported, false otherwise. The default implementation returns false. + */ + virtual bool canCreateFence() noexcept; + + /** + * Creates a Fence (e.g. eglCreateSyncKHR). This must be implemented if `canCreateFence` + * returns true. Fences are used for frame pacing. + * + * @return A Fence object. The default implementation returns nullptr. + */ + virtual Fence* UTILS_NULLABLE createFence() noexcept; + + /** + * Destroys a Fence object. The default implementation does nothing. + * + * @param fence Fence to destroy. + */ + virtual void destroyFence(Fence* UTILS_NONNULL fence) noexcept; + + /** + * Waits on a Fence. + * + * @param fence Fence to wait on. + * @param timeout Timeout. + * @return Whether the fence signaled or timed out. See backend::FenceStatus. + * The default implementation always return backend::FenceStatus::ERROR. + */ + virtual backend::FenceStatus waitFence(Fence* UTILS_NONNULL fence, uint64_t timeout) noexcept; + + + // -------------------------------------------------------------------------------------------- + // Streaming support + + /** + * Creates a Stream from a native Stream. + * + * WARNING: This is called synchronously from the application thread (NOT the Driver thread) + * + * @param nativeStream The native stream, this parameter depends on the concrete implementation. + * @return A new Stream object. + */ + virtual Stream* UTILS_NULLABLE createStream(void* UTILS_NULLABLE nativeStream) noexcept; + + /** + * Destroys a Stream. + * @param stream Stream to destroy. + */ + virtual void destroyStream(Stream* UTILS_NONNULL stream) noexcept; + + /** + * The specified stream takes ownership of the texture (tname) object + * Once attached, the texture is automatically updated with the Stream's content, which + * could be a video stream for instance. + * + * @param stream Stream to take ownership of the texture + * @param tname GL texture id to "bind" to the Stream. + */ + virtual void attach(Stream* UTILS_NONNULL stream, intptr_t tname) noexcept; + + /** + * Destroys the texture associated to the stream + * @param stream Stream to detach from its texture + */ + virtual void detach(Stream* UTILS_NONNULL stream) noexcept; + + /** + * Updates the content of the texture attached to the stream. + * @param stream Stream to update + * @param timestamp Output parameter: Timestamp of the image bound to the texture. + */ + virtual void updateTexImage(Stream* UTILS_NONNULL stream, + int64_t* UTILS_NONNULL timestamp) noexcept; + + + // -------------------------------------------------------------------------------------------- + // External Image support + + /** + * Creates an external texture handle. External textures don't have any parameters because + * these are undefined until setExternalImage() is called. + * @return a pointer to an ExternalTexture structure filled with valid token. However, the + * implementation could just return { 0, GL_TEXTURE_2D } at this point. The actual + * values can be delayed until setExternalImage. + */ + virtual ExternalTexture* UTILS_NULLABLE createExternalImageTexture() noexcept; + + /** + * Destroys an external texture handle and associated data. + * @param texture a pointer to the handle to destroy. + */ + virtual void destroyExternalImage(ExternalTexture* UTILS_NONNULL texture) noexcept; + + // called on the application thread to allow Filament to take ownership of the image + + /** + * Takes ownership of the externalImage. The externalImage parameter depends on the Platform's + * concrete implementation. Ownership is released when destroyExternalImage() is called. + * + * WARNING: This is called synchronously from the application thread (NOT the Driver thread) + * + * @param externalImage A token representing the platform's external image. + * @see destroyExternalImage + */ + virtual void retainExternalImage(void* UTILS_NONNULL externalImage) noexcept; + + /** + * Called to bind the platform-specific externalImage to an ExternalTexture. + * ExternalTexture::id is guaranteed to be bound when this method is called and ExternalTexture + * is updated with new values for id/target if necessary. + * + * WARNING: this method is not allowed to change the bound texture, or must restore the previous + * binding upon return. This is to avoid problem with a backend doing state caching. + * + * @param externalImage The platform-specific external image. + * @param texture an in/out pointer to ExternalTexture, id and target can be updated if necessary. + * @return true on success, false on error. + */ + virtual bool setExternalImage(void* UTILS_NONNULL externalImage, + ExternalTexture* UTILS_NONNULL texture) noexcept; + + /** + * The method allows platforms to convert a user-supplied external image object into a new type + * (e.g. HardwareBuffer => EGLImage). The default implementation returns source. + * @param source Image to transform. + * @return Transformed image. + */ + virtual AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept; + + // -------------------------------------------------------------------------------------------- + + /** + * Returns true if additional OpenGL contexts can be created. Default: false. + * @return true if additional OpenGL contexts can be created. + * @see createContext + */ + virtual bool isExtraContextSupported() const noexcept; + + /** + * Creates an OpenGL context with the same configuration than the main context and makes it + * current to the current thread. Must not be called from the main driver thread. + * createContext() is only supported if isExtraContextSupported() returns true. + * These additional contexts will be automatically terminated in terminate. + * + * @param shared whether the new context is shared with the main context. + * @see isExtraContextSupported() + * @see terminate() + */ + virtual void createContext(bool shared); + + /** + * Detach and destroy the current context if any and releases all resources associated to + * this thread. + */ + virtual void releaseContext() noexcept; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformCocoaGL.h b/package/android/libs/filament/include/backend/platforms/PlatformCocoaGL.h new file mode 100644 index 00000000..72a12185 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformCocoaGL.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H + +#include +#include + +#include + +namespace filament::backend { + +struct PlatformCocoaGLImpl; + +/** + * A concrete implementation of OpenGLPlatform that supports macOS's Cocoa. + */ +class PlatformCocoaGL : public OpenGLPlatform { +public: + PlatformCocoaGL(); + ~PlatformCocoaGL() noexcept override; + +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + // Currently returns 0 + int getOSVersion() const noexcept override; + + bool pumpEvents() noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + void retainExternalImage(void* externalImage) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + +private: + PlatformCocoaGLImpl* pImpl = nullptr; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h b/package/android/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h new file mode 100644 index 00000000..a60a6369 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H + +#include + +#include + +#include + +namespace filament::backend { + +struct PlatformCocoaTouchGLImpl; + +class PlatformCocoaTouchGL : public OpenGLPlatform { +public: + PlatformCocoaTouchGL(); + ~PlatformCocoaTouchGL() noexcept override; + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + uint32_t createDefaultRenderTarget() noexcept override; + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + void retainExternalImage(void* externalImage) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + +private: + PlatformCocoaTouchGLImpl* pImpl = nullptr; +}; + +using ContextManager = PlatformCocoaTouchGL; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformEGL.h b/package/android/libs/filament/include/backend/platforms/PlatformEGL.h new file mode 100644 index 00000000..cb124665 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformEGL.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports EGL. + */ +class PlatformEGL : public OpenGLPlatform { +public: + + PlatformEGL() noexcept; + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + void releaseContext() noexcept override; + + // Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default. + virtual bool isOpenGL() const noexcept; + +protected: + + // -------------------------------------------------------------------------------------------- + // Helper for EGL configs and attributes parameters + + class Config { + public: + Config(); + Config(std::initializer_list> list); + EGLint& operator[](EGLint name); + EGLint operator[](EGLint name) const; + void erase(EGLint name) noexcept; + EGLint const* data() const noexcept { + return reinterpret_cast(mConfig.data()); + } + size_t size() const noexcept { + return mConfig.size(); + } + private: + std::vector> mConfig = {{ EGL_NONE, EGL_NONE }}; + }; + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + /** + * Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation + * that supports OpenGL/OpenGL ES. + */ + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + /** + * This returns zero. This method can be overridden to return something more useful. + * @return zero + */ + int getOSVersion() const noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + bool isSRGBSwapChainSupported() const noexcept override; + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + + bool canCreateFence() noexcept override; + Fence* createFence() noexcept override; + void destroyFence(Fence* fence) noexcept override; + FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override; + + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + + /** + * Logs glGetError() to slog.e + * @param name a string giving some context on the error. Typically __func__. + */ + static void logEglError(const char* name) noexcept; + static void logEglError(const char* name, EGLint error) noexcept; + static const char* getEglErrorName(EGLint error) noexcept; + + /** + * Calls glGetError() to clear the current error flags. logs a warning to log.w if + * an error was pending. + */ + static void clearGlError() noexcept; + + /** + * Always use this instead of eglMakeCurrent(). + */ + EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept; + + // TODO: this should probably use getters instead. + EGLDisplay mEGLDisplay = EGL_NO_DISPLAY; + EGLContext mEGLContext = EGL_NO_CONTEXT; + EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE; + EGLSurface mCurrentReadSurface = EGL_NO_SURFACE; + EGLSurface mEGLDummySurface = EGL_NO_SURFACE; + // mEGLConfig is valid only if ext.egl.KHR_no_config_context is false + EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR; + Config mContextAttribs; + std::vector mAdditionalContexts; + + // supported extensions detected at runtime + struct { + struct { + bool OES_EGL_image_external_essl3 = false; + } gl; + struct { + bool ANDROID_recordable = false; + bool KHR_create_context = false; + bool KHR_gl_colorspace = false; + bool KHR_no_config_context = false; + bool KHR_surfaceless_context = false; + } egl; + } ext; + + void initializeGlExtensions() noexcept; + +protected: + EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformEGLAndroid.h b/package/android/libs/filament/include/backend/platforms/PlatformEGLAndroid.h new file mode 100644 index 00000000..32f83038 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformEGLAndroid.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H + +#include +#include +#include +#include + +#include +#include + +namespace filament::backend { + +class ExternalStreamManagerAndroid; + +/** + * A concrete implementation of OpenGLPlatform and subclass of PlatformEGL that supports + * EGL on Android. It adds Android streaming functionality to PlatformEGL. + */ +class PlatformEGLAndroid : public PlatformEGL { +public: + + PlatformEGLAndroid() noexcept; + ~PlatformEGLAndroid() noexcept override; + +protected: + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + /** + * Returns the Android SDK version. + * @return Android SDK version. + */ + int getOSVersion() const noexcept override; + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + /** + * Set the presentation time using `eglPresentationTimeANDROID` + * @param presentationTimeInNanosecond + */ + void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept override; + + + Stream* createStream(void* nativeStream) noexcept override; + void destroyStream(Stream* stream) noexcept override; + void attach(Stream* stream, intptr_t tname) noexcept override; + void detach(Stream* stream) noexcept override; + void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override; + + /** + * Converts a AHardwareBuffer to EGLImage + * @param source source.image is a AHardwareBuffer + * @return source.image contains an EGLImage + */ + AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override; + +private: + int mOSVersion; + ExternalStreamManagerAndroid& mExternalStreamManager; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformEGLHeadless.h b/package/android/libs/filament/include/backend/platforms/PlatformEGLHeadless.h new file mode 100644 index 00000000..40d285b9 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformEGLHeadless.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H +#define TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H + +#include "PlatformEGL.h" + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports EGL with only headless swapchains. + */ +class PlatformEGLHeadless : public PlatformEGL { +public: + PlatformEGLHeadless() noexcept; + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + +protected: + bool isOpenGL() const noexcept override; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformGLX.h b/package/android/libs/filament/include/backend/platforms/PlatformGLX.h new file mode 100644 index 00000000..b2be5e40 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformGLX.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H + +#include + +#include "bluegl/BlueGL.h" +#include + +#include + +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports GLX. + */ +class PlatformGLX : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final override { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + +private: + Display *mGLXDisplay; + GLXContext mGLXContext; + GLXFBConfig* mGLXConfig; + GLXPbuffer mDummySurface; + std::vector mPBuffers; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformWGL.h b/package/android/libs/filament/include/backend/platforms/PlatformWGL.h new file mode 100644 index 00000000..6c16c305 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformWGL.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WGL_H + +#include + +#include +#include "utils/unwindows.h" + +#include +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports WGL. + */ +class PlatformWGL : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final override { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + +protected: + HGLRC mContext = NULL; + HWND mHWnd = NULL; + HDC mWhdc = NULL; + PIXELFORMATDESCRIPTOR mPfd = {}; + std::vector mAdditionalContexts; + std::vector mAttribs; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H diff --git a/package/android/libs/filament/include/backend/platforms/PlatformWebGL.h b/package/android/libs/filament/include/backend/platforms/PlatformWebGL.h new file mode 100644 index 00000000..92bff0c4 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/PlatformWebGL.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H + +#include + +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports WebGL. + */ +class PlatformWebGL : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H diff --git a/package/android/libs/filament/include/backend/platforms/VulkanPlatform.h b/package/android/libs/filament/include/backend/platforms/VulkanPlatform.h new file mode 100644 index 00000000..6201d644 --- /dev/null +++ b/package/android/libs/filament/include/backend/platforms/VulkanPlatform.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H +#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +using SwapChain = Platform::SwapChain; + +/** + * Private implementation details for the provided vulkan platform. + */ +struct VulkanPlatformPrivate; + +/** + * A Platform interface that creates a Vulkan backend. + */ +class VulkanPlatform : public Platform, utils::PrivateImplementation { +public: + + /** + * A collection of handles to objects and metadata that comprises a Vulkan context. The client + * can instantiate this struct and pass to Engine::Builder::sharedContext if they wishes to + * share their vulkan context. This is specifically necessary if the client wishes to override + * the swapchain API. + */ + struct VulkanSharedContext { + VkInstance instance = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice logicalDevice = VK_NULL_HANDLE; + uint32_t graphicsQueueFamilyIndex = 0xFFFFFFFF; + // In the usual case, the client needs to allocate at least one more graphics queue + // for Filament, and this index is the param to pass into vkGetDeviceQueue. In the case + // where the gpu only has one graphics queue. Then the client needs to ensure that no + // concurrent access can occur. + uint32_t graphicsQueueIndex = 0xFFFFFFFF; + }; + + /** + * Shorthand for the pointer to the Platform SwapChain struct, we use it also as a handle (i.e. + * identifier for the swapchain). + */ + using SwapChainPtr = Platform::SwapChain*; + + /** + * Collection of images, formats, and extent (width/height) that defines the swapchain. + */ + struct SwapChainBundle { + utils::FixedCapacityVector colors; + VkImage depth = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkFormat depthFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent = {0, 0}; + }; + + VulkanPlatform(); + + ~VulkanPlatform() override; + + Driver* createDriver(void* sharedContext, + Platform::DriverConfig const& driverConfig) noexcept override; + + int getOSVersion() const noexcept override { + return 0; + } + + // ---------------------------------------------------- + // ---------- Platform Customization options ---------- + struct Customization { + /** + * The client can specify the GPU (i.e. VkDevice) for the platform. We allow the + * following preferences: + * 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`. Empty string + * by default. + * 2) Index of the device in the list as returned by + * `vkEnumeratePhysicalDevices`. -1 by default to indicate no preference. + */ + struct GPUPreference { + utils::CString deviceName; + int8_t index = -1; + } gpu; + + /** + * Whether the platform supports sRGB swapchain. Default is true. + */ + bool isSRGBSwapChainSupported = true; + + /** + * When the platform window is resized, we will flush and wait on the command queues + * before recreating the swapchain. Default is true. + */ + bool flushAndWaitOnWindowResize = true; + }; + + /** + * Client can override to indicate customized behavior or parameter for their platform. + * @return `Customization` struct that indicates the client's platform + * customizations. + */ + virtual Customization getCustomization() const noexcept { + return {}; + } + + // -------- End platform customization options -------- + // ---------------------------------------------------- + + /** + * Get the images handles and format of the memory backing the swapchain. This should be called + * after createSwapChain() or after recreateIfResized(). + * @param swapchain The handle returned by createSwapChain() + * @return An array of VkImages + */ + virtual SwapChainBundle getSwapChainBundle(SwapChainPtr handle); + + /** + * Acquire the next image for rendering. The `index` will be written with an non-negative + * integer that the backend can use to index into the `SwapChainBundle.colors` array. The + * corresponding VkImage will be used as the output color attachment. The client should signal + * the `clientSignal` semaphore when the image is ready to be used by the backend. + * @param handle The handle returned by createSwapChain() + * @param clientSignal The semaphore that the client will signal to indicate that the backend + * may render into the image. + * @param index Pointer to memory that will be filled with the index that corresponding + * to an image in the `SwapChainBundle.colors` array. + * @return Result of acquire + */ + virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index); + + /** + * Present the image corresponding to `index` to the display. The client should wait on + * `finishedDrawing` before presenting. + * @param handle The handle returned by createSwapChain() + * @param index Index that corresponding to an image in the + * `SwapChainBundle.colors` array. + * @param finishedDrawing Backend passes in a semaphore that the client will signal to + * indicate that the client may render into the image. + * @return Result of present + */ + virtual VkResult present(SwapChainPtr handle, uint32_t index, VkSemaphore finishedDrawing); + + /** + * Check if the surface size has changed. + * @param handle The handle returned by createSwapChain() + * @return Whether the swapchain has been resized + */ + virtual bool hasResized(SwapChainPtr handle); + + /** + * Carry out a recreation of the swapchain. + * @param handle The handle returned by createSwapChain() + * @return Result of the recreation + */ + virtual VkResult recreate(SwapChainPtr handle); + + /** + * Create a swapchain given a platform window, or if given a null `nativeWindow`, then we + * try to create a headless swapchain with the given `extent`. + * @param flags Optional parameters passed to the client as defined in + * Filament::SwapChain.h. + * @param extent Optional width and height that indicates the size of the headless swapchain. + * @return Result of the operation + */ + virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0, + VkExtent2D extent = {0, 0}); + + /** + * Destroy the swapchain. + * @param handle The handle returned by createSwapChain() + */ + virtual void destroy(SwapChainPtr handle); + + /** + * Clean up any resources owned by the Platform. For example, if the Vulkan instance handle was + * generated by the platform, we need to clean it up in this method. + */ + virtual void terminate(); + + /** + * @return The instance (VkInstance) for the Vulkan backend. + */ + VkInstance getInstance() const noexcept; + + /** + * @return The logical device (VkDevice) that was selected as the backend device. + */ + VkDevice getDevice() const noexcept; + + /** + * @return The physical device (i.e gpu) that was selected as the backend physical device. + */ + VkPhysicalDevice getPhysicalDevice() const noexcept; + + /** + * @return The family index of the graphics queue selected for the Vulkan backend. + */ + uint32_t getGraphicsQueueFamilyIndex() const noexcept; + + /** + * @return The index of the graphics queue (if there are multiple graphics queues) + * selected for the Vulkan backend. + */ + uint32_t getGraphicsQueueIndex() const noexcept; + + /** + * @return The queue that was selected for the Vulkan backend. + */ + VkQueue getGraphicsQueue() const noexcept; + +private: + // Platform dependent helper methods + using ExtensionSet = std::unordered_set; + static ExtensionSet getRequiredInstanceExtensions(); + + using SurfaceBundle = std::tuple; + static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, + uint64_t flags) noexcept; + + friend struct VulkanPlatformPrivate; +}; + +}// namespace filament::backend + +#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H diff --git a/package/android/libs/filament/include/camutils/Bookmark.h b/package/android/libs/filament/include/camutils/Bookmark.h new file mode 100644 index 00000000..44ec1d62 --- /dev/null +++ b/package/android/libs/filament/include/camutils/Bookmark.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef CAMUTILS_BOOKMARK_H +#define CAMUTILS_BOOKMARK_H + +#include + +#include +#include + +namespace filament { +namespace camutils { + +template class FreeFlightManipulator; +template class OrbitManipulator; +template class MapManipulator; +template class Manipulator; + +enum class Mode { ORBIT, MAP, FREE_FLIGHT }; + +/** + * Opaque memento to a viewing position and orientation (e.g. the "home" camera position). + * + * This little struct is meant to be passed around by value and can be used to track camera + * animation between waypoints. In map mode this implements Van Wijk interpolation. + * + * @see Manipulator::getCurrentBookmark, Manipulator::jumpToBookmark + */ +template +struct CAMUTILS_PUBLIC Bookmark { + /** + * Interpolates between two bookmarks. The t argument must be between 0 and 1 (inclusive), and + * the two endpoints must have the same mode (ORBIT or MAP). + */ + static Bookmark interpolate(Bookmark a, Bookmark b, double t); + + /** + * Recommends a duration for animation between two MAP endpoints. The return value is a unitless + * multiplier. + */ + static double duration(Bookmark a, Bookmark b); + +private: + struct MapParams { + FLOAT extent; + filament::math::vec2 center; + }; + struct OrbitParams { + FLOAT phi; + FLOAT theta; + FLOAT distance; + filament::math::vec3 pivot; + }; + struct FlightParams { + FLOAT pitch; + FLOAT yaw; + filament::math::vec3 position; + }; + Mode mode; + MapParams map; + OrbitParams orbit; + FlightParams flight; + friend class FreeFlightManipulator; + friend class OrbitManipulator; + friend class MapManipulator; +}; + +} // namespace camutils +} // namespace filament + +#endif // CAMUTILS_BOOKMARK_H diff --git a/package/android/libs/filament/include/camutils/Manipulator.h b/package/android/libs/filament/include/camutils/Manipulator.h new file mode 100644 index 00000000..2cc8a4da --- /dev/null +++ b/package/android/libs/filament/include/camutils/Manipulator.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef CAMUTILS_MANIPULATOR_H +#define CAMUTILS_MANIPULATOR_H + +#include +#include + +#include +#include +#include + +#include + +namespace filament { +namespace camutils { + +enum class Fov { VERTICAL, HORIZONTAL }; + +/** + * Helper that enables camera interaction similar to sketchfab or Google Maps. + * + * Clients notify the camera manipulator of various mouse or touch events, then periodically call + * its getLookAt() method so that they can adjust their camera(s). Three modes are supported: ORBIT, + * MAP, and FREE_FLIGHT. To construct a manipulator instance, the desired mode is passed into the + * create method. + * + * Usage example: + * + * using CameraManipulator = camutils::Manipulator; + * CameraManipulator* manip; + * + * void init() { + * manip = CameraManipulator::Builder() + * .viewport(1024, 768) + * .build(camutils::Mode::ORBIT); + * } + * + * void onMouseDown(int x, int y) { + * manip->grabBegin(x, y, false); + * } + * + * void onMouseMove(int x, int y) { + * manip->grabUpdate(x, y); + * } + * + * void onMouseUp(int x, int y) { + * manip->grabEnd(); + * } + * + * void gameLoop() { + * while (true) { + * filament::math::float3 eye, center, up; + * manip->getLookAt(&eye, ¢er, &up); + * camera->lookAt(eye, center, up); + * render(); + * } + * } + * + * @see Bookmark + */ +template +class CAMUTILS_PUBLIC Manipulator { +public: + using vec2 = filament::math::vec2; + using vec3 = filament::math::vec3; + using vec4 = filament::math::vec4; + + /** Opaque handle to a viewing position and orientation to facilitate camera animation. */ + using Bookmark = filament::camutils::Bookmark; + + /** Optional raycasting function to enable perspective-correct panning. */ + typedef bool (*RayCallback)(const vec3& origin, const vec3& dir, FLOAT* t, void* userdata); + + /** Builder state, direct access is allowed but Builder methods are preferred. **/ + struct Config { + int viewport[2]; + vec3 targetPosition; + vec3 upVector; + FLOAT zoomSpeed; + vec3 orbitHomePosition; + vec2 orbitSpeed; + Fov fovDirection; + FLOAT fovDegrees; + FLOAT farPlane; + vec2 mapExtent; + FLOAT mapMinDistance; + vec3 flightStartPosition; + FLOAT flightStartPitch; + FLOAT flightStartYaw; + FLOAT flightMaxSpeed; + FLOAT flightSpeedSteps; + vec2 flightPanSpeed; + FLOAT flightMoveDamping; + vec4 groundPlane; + RayCallback raycastCallback; + void* raycastUserdata; + }; + + struct Builder { + // Common properties + Builder& viewport(int width, int height); //! Width and height of the viewing area + Builder& targetPosition(FLOAT x, FLOAT y, FLOAT z); //! World-space position of interest, defaults to (0,0,0) + Builder& upVector(FLOAT x, FLOAT y, FLOAT z); //! Orientation for the home position, defaults to (0,1,0) + Builder& zoomSpeed(FLOAT val); //! Multiplied with scroll delta, defaults to 0.01 + + // Orbit mode properties + Builder& orbitHomePosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,1) + Builder& orbitSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01 + + // Map mode properties + Builder& fovDirection(Fov fov); //! The axis that's held constant when viewport changes + Builder& fovDegrees(FLOAT degrees); //! The full FOV (not the half-angle) + Builder& farPlane(FLOAT distance); //! The distance to the far plane + Builder& mapExtent(FLOAT worldWidth, FLOAT worldHeight); //! The ground size for computing home position + Builder& mapMinDistance(FLOAT mindist); //! Constrains the zoom-in level + + // Free flight properties + Builder& flightStartPosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,0) + Builder& flightStartOrientation(FLOAT pitch, FLOAT yaw); //! Initial orientation in pitch and yaw, defaults to (0,0) + Builder& flightMaxMoveSpeed(FLOAT maxSpeed); //! The maximum camera speed in world units per second, defaults to 10 + Builder& flightSpeedSteps(int steps); //! The number of speed steps adjustable with scroll wheel, defaults to 80 + Builder& flightPanSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01,0.01 + Builder& flightMoveDamping(FLOAT damping); //! Applies a deceleration to camera movement, defaults to 0 (no damping) + //! Lower values give slower damping times, a good default is 15 + //! Too high a value may lead to instability + + // Raycast properties + Builder& groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d); //! Plane equation used as a raycast fallback + Builder& raycastCallback(RayCallback cb, void* userdata); //! Raycast function for accurate grab-and-pan + + /** + * Creates a new camera manipulator, either ORBIT, MAP, or FREE_FLIGHT. + * + * Clients can simply use "delete" to destroy the manipulator. + */ + Manipulator* build(Mode mode); + + Config details = {}; + }; + + virtual ~Manipulator() = default; + + /** + * Gets the immutable mode of the manipulator. + */ + Mode getMode() const { return mMode; } + + /** + * Sets the viewport dimensions. The manipulator uses this to process grab events and raycasts. + */ + void setViewport(int width, int height); + + /** + * Gets the current orthonormal basis; this is usually called once per frame. + */ + void getLookAt(vec3* eyePosition, vec3* targetPosition, vec3* upward) const; + + /** + * Given a viewport coordinate, picks a point in the ground plane, or in the actual scene if the + * raycast callback was provided. + */ + bool raycast(int x, int y, vec3* result) const; + + /** + * Given a viewport coordinate, computes a picking ray (origin + direction). + */ + void getRay(int x, int y, vec3* origin, vec3* dir) const; + + /** + * Starts a grabbing session (i.e. the user is dragging around in the viewport). + * + * In MAP mode, this starts a panning session. + * In ORBIT mode, this starts either rotating or strafing. + * In FREE_FLIGHT mode, this starts a nodal panning session. + * + * @param x X-coordinate for point of interest in viewport space + * @param y Y-coordinate for point of interest in viewport space + * @param strafe ORBIT mode only; if true, starts a translation rather than a rotation + */ + virtual void grabBegin(int x, int y, bool strafe) = 0; + + /** + * Updates a grabbing session. + * + * This must be called at least once between grabBegin / grabEnd to dirty the camera. + */ + virtual void grabUpdate(int x, int y) = 0; + + /** + * Ends a grabbing session. + */ + virtual void grabEnd() = 0; + + /** + * Keys used to translate the camera in FREE_FLIGHT mode. + * FORWARD and BACKWARD dolly the camera forwards and backwards. + * LEFT and RIGHT strafe the camera left and right. + * UP and DOWN boom the camera upwards and downwards. + */ + enum class Key { + FORWARD, + LEFT, + BACKWARD, + RIGHT, + UP, + DOWN, + + COUNT + }; + + /** + * Signals that a key is now in the down state. + * + * In FREE_FLIGHT mode, the camera is translated forward and backward and strafed left and right + * depending on the depressed keys. This allows WASD-style movement. + */ + virtual void keyDown(Key key); + + /** + * Signals that a key is now in the up state. + * + * @see keyDown + */ + virtual void keyUp(Key key); + + /** + * In MAP and ORBIT modes, dollys the camera along the viewing direction. + * In FREE_FLIGHT mode, adjusts the move speed of the camera. + * + * @param x X-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode + * @param y Y-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode + * @param scrolldelta In MAP and ORBIT modes, negative means "zoom in", positive means "zoom out" + * In FREE_FLIGHT mode, negative means "slower", positive means "faster" + */ + virtual void scroll(int x, int y, FLOAT scrolldelta) = 0; + + /** + * Processes input and updates internal state. + * + * This must be called once every frame before getLookAt is valid. + * + * @param deltaTime The amount of time, in seconds, passed since the previous call to update. + */ + virtual void update(FLOAT deltaTime); + + /** + * Gets a handle that can be used to reset the manipulator back to its current position. + * + * @see jumpToBookmark + */ + virtual Bookmark getCurrentBookmark() const = 0; + + /** + * Gets a handle that can be used to reset the manipulator back to its home position. + * + * @see jumpToBookmark + */ + virtual Bookmark getHomeBookmark() const = 0; + + /** + * Sets the manipulator position and orientation back to a stashed state. + * + * @see getCurrentBookmark, getHomeBookmark + */ + virtual void jumpToBookmark(const Bookmark& bookmark) = 0; + +protected: + Manipulator(Mode mode, const Config& props); + + virtual void setProperties(const Config& props); + + vec3 raycastFarPlane(int x, int y) const; + + const Mode mMode; + Config mProps; + vec3 mEye; + vec3 mTarget; +}; + +} // namespace camutils +} // namespace filament + +#endif /* CAMUTILS_MANIPULATOR_H */ diff --git a/package/android/libs/filament/include/camutils/compiler.h b/package/android/libs/filament/include/camutils/compiler.h new file mode 100644 index 00000000..5e5edf94 --- /dev/null +++ b/package/android/libs/filament/include/camutils/compiler.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CAMUTILS_COMPILER_H +#define CAMUTILS_COMPILER_H + +#if __has_attribute(visibility) +# define CAMUTILS_PUBLIC __attribute__((visibility("default"))) +#else +# define CAMUTILS_PUBLIC +#endif + +#endif // CAMUTILS_COMPILER_H diff --git a/package/android/libs/filament/include/filamat/Enums.h b/package/android/libs/filament/include/filamat/Enums.h new file mode 100644 index 00000000..04b5ff8b --- /dev/null +++ b/package/android/libs/filament/include/filamat/Enums.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_ENUMMANAGER_H +#define TNT_ENUMMANAGER_H + +#include +#include +#include + +#include + +namespace filamat { + +using Property = MaterialBuilder::Property; +using UniformType = MaterialBuilder::UniformType; +using SamplerType = MaterialBuilder::SamplerType; +using SubpassType = MaterialBuilder::SubpassType; +using SamplerFormat = MaterialBuilder::SamplerFormat; +using ParameterPrecision = MaterialBuilder::ParameterPrecision; +using OutputTarget = MaterialBuilder::OutputTarget; +using OutputQualifier = MaterialBuilder::VariableQualifier; +using OutputType = MaterialBuilder::OutputType; +using ConstantType = MaterialBuilder::ConstantType; + +// Convenience methods to convert std::string to Enum and also iterate over Enum values. +class Enums { +public: + + // Returns true if string "s" is a valid string representation of an element of enum T. + template + static bool isValid(const std::string& s) noexcept { + std::unordered_map& map = getMap(); + return map.find(s) != map.end(); + } + + // Return enum matching its string representation. Returns undefined if s is not a valid enum T + // value. You should always call isValid() first to validate a string before calling toEnum(). + template + static T toEnum(const std::string& s) noexcept { + std::unordered_map& map = getMap(); + return map.at(s); + } + + template + static std::string toString(T t) noexcept; + + // Return a map of all values in an enum with their string representation. + template + static std::unordered_map& map() noexcept { + std::unordered_map& map = getMap(); + return map; + }; + +private: + template + static std::unordered_map& getMap() noexcept; + + static std::unordered_map mStringToProperty; + static std::unordered_map mStringToUniformType; + static std::unordered_map mStringToSamplerType; + static std::unordered_map mStringToSubpassType; + static std::unordered_map mStringToSamplerFormat; + static std::unordered_map mStringToSamplerPrecision; + static std::unordered_map mStringToOutputTarget; + static std::unordered_map mStringToOutputQualifier; + static std::unordered_map mStringToOutputType; + static std::unordered_map mStringToConstantType; +}; + +template +std::string Enums::toString(T t) noexcept { + std::unordered_map& map = getMap(); + auto result = std::find_if(map.begin(), map.end(), [t](auto& pair) { + return pair.second == t; + }); + if (result != map.end()) { + return result->first; + } + return ""; +} + +} // namespace filamat + +#endif //TNT_ENUMMANAGER_H diff --git a/package/android/libs/filament/include/filamat/IncludeCallback.h b/package/android/libs/filament/include/filamat/IncludeCallback.h new file mode 100644 index 00000000..659ba289 --- /dev/null +++ b/package/android/libs/filament/include/filamat/IncludeCallback.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMAT_INCLUDER_H +#define TNT_FILAMAT_INCLUDER_H + +#include + +#include + +namespace filamat { + +struct IncludeResult { + // The include name of the root file, as if it were being included. + // I.e., 'foobar.h' in the case of #include "foobar.h" + const utils::CString includeName; + + // The following fields should be filled out by the IncludeCallback when processing an include, + // or when calling resolveIncludes for the root file. + + // The full contents of the include file. This may contain additional, recursive include + // directives. + utils::CString text; + + // The line number for the first line of text (first line is 0). + size_t lineNumberOffset = 0; + + // The name of the include file. This gets passed as "includerName" for any includes inside of + // source. This field isn't used by the include system; it's up to the callback to give meaning + // to this value and interpret it accordingly. In the case of DirIncluder, this is an empty + // string to represent the root include file, and a canonical path for subsequent included + // files. + utils::CString name; +}; + +/** + * A callback invoked by the include system when an #include "file.h" directive is found. + * + * For example, if a file main.h includes file.h on line 10, then IncludeCallback would be called + * with the following: + * includeCallback("main.h", {.includeName = "file.h" }) + * It's then up to the IncludeCallback to fill out the .text, .name, and (optionally) + * lineNumberOffset fields. + * + * @param includedBy is the value that was given to IncludeResult.name for this source file, or + * the empty string for the root source file. + * @param result is the IncludeResult that the callback should fill out. + * @return true, if the include was resolved successfully, false otherwise. + * + * For an example of implementing this callback, see tools/matc/src/matc/DirIncluder.h. + */ +using IncludeCallback = std::function; + +} // namespace filamat + +#endif diff --git a/package/android/libs/filament/include/filamat/MaterialBuilder.h b/package/android/libs/filament/include/filamat/MaterialBuilder.h new file mode 100644 index 00000000..bd586fe9 --- /dev/null +++ b/package/android/libs/filament/include/filamat/MaterialBuilder.h @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2017 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. + */ + +//! \file + +#ifndef TNT_FILAMAT_MATERIAL_PACKAGE_BUILDER_H +#define TNT_FILAMAT_MATERIAL_PACKAGE_BUILDER_H + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace utils { +class JobSystem; +} + +namespace filament { +class BufferInterfaceBlock; +} + +namespace filamat { + +struct MaterialInfo; +struct Variant; +class ChunkContainer; + +class UTILS_PUBLIC MaterialBuilderBase { +public: + /** + * High-level hint that works in concert with TargetApi to determine the shader models (used to + * generate GLSL) and final output representations (spirv and/or text). + * When generating the GLSL this is used to differentiate OpenGL from OpenGLES, it is also + * used to make some performance adjustments. + */ + enum class Platform { + DESKTOP, + MOBILE, + ALL + }; + + /** + * TargetApi defines which language after transpilation will be used, it is used to + * account for some differences between these languages when generating the GLSL. + */ + enum class TargetApi : uint8_t { + OPENGL = 0x01u, + VULKAN = 0x02u, + METAL = 0x04u, + ALL = OPENGL | VULKAN | METAL + }; + + /* + * Generally we generate GLSL that will be converted to SPIRV, optimized and then + * transpiled to the backend's language such as MSL, ESSL300, GLSL410 or SPIRV, in this + * case the generated GLSL uses ESSL310 or GLSL450 and has Vulkan semantics and + * TargetLanguage::SPIRV must be used. + * + * However, in some cases (e.g. when no optimization is asked) we generate the *final* GLSL + * directly, this GLSL must be ESSL300 or GLSL410 and cannot use any Vulkan syntax, for this + * situation we use TargetLanguage::GLSL. In this case TargetApi is guaranteed to be OPENGL. + * + * Note that TargetLanguage::GLSL is not the common case, as it is generally not used in + * release builds. + * + * Also note that glslang performs semantics analysis on whichever GLSL ends up being generated. + */ + enum class TargetLanguage { + GLSL, // GLSL with OpenGL 4.1 / OpenGL ES 3.0 semantics + SPIRV // GLSL with Vulkan semantics + }; + + enum class Optimization { + NONE, + PREPROCESSOR, + SIZE, + PERFORMANCE + }; + + /** + * Initialize MaterialBuilder. + * + * init must be called first before building any materials. + */ + static void init(); + + /** + * Release internal MaterialBuilder resources. + * + * Call shutdown when finished building materials to release all internal resources. After + * calling shutdown, another call to MaterialBuilder::init must precede another material build. + */ + static void shutdown(); + +protected: + // Looks at platform and target API, then decides on shader models and output formats. + void prepare(bool vulkanSemantics, filament::backend::FeatureLevel featureLevel); + + using ShaderModel = filament::backend::ShaderModel; + Platform mPlatform = Platform::DESKTOP; + TargetApi mTargetApi = (TargetApi) 0; + Optimization mOptimization = Optimization::PERFORMANCE; + bool mPrintShaders = false; + bool mGenerateDebugInfo = false; + bool mIncludeEssl1 = true; + utils::bitset32 mShaderModels; + struct CodeGenParams { + ShaderModel shaderModel; + TargetApi targetApi; + TargetLanguage targetLanguage; + filament::backend::FeatureLevel featureLevel; + }; + std::vector mCodeGenPermutations; + + // Keeps track of how many times MaterialBuilder::init() has been called without a call to + // MaterialBuilder::shutdown(). Internally, glslang does something similar. We keep track for + // ourselves, so we can inform the user if MaterialBuilder::init() hasn't been called before + // attempting to build a material. + static std::atomic materialBuilderClients; +}; + +// Utility function that looks at an Engine backend to determine TargetApi +inline constexpr MaterialBuilderBase::TargetApi targetApiFromBackend( + filament::backend::Backend backend) noexcept { + using filament::backend::Backend; + using TargetApi = MaterialBuilderBase::TargetApi; + switch (backend) { + case Backend::DEFAULT: return TargetApi::ALL; + case Backend::OPENGL: return TargetApi::OPENGL; + case Backend::VULKAN: return TargetApi::VULKAN; + case Backend::METAL: return TargetApi::METAL; + case Backend::NOOP: return TargetApi::OPENGL; + } +} + +/** + * MaterialBuilder builds Filament materials from shader code. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filamat; + * + * // Must be called before any materials can be built. + * MaterialBuilder::init(); + + * MaterialBuilder builder; + * builder + * .name("My material") + * .material("void material (inout MaterialInputs material) {" + * " prepareMaterial(material);" + * " material.baseColor.rgb = float3(1.0, 0.0, 0.0);" + * "}") + * .shading(MaterialBuilder::Shading::LIT) + * .targetApi(MaterialBuilder::TargetApi::ALL) + * .platform(MaterialBuilder::Platform::ALL); + + * Package package = builder.build(); + * if (package.isValid()) { + * // success! + * } + + * // Call when finished building all materials to release internal + * // MaterialBuilder resources. + * MaterialBuilder::shutdown(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see filament::Material + */ +class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { +public: + MaterialBuilder(); + ~MaterialBuilder(); + + MaterialBuilder(const MaterialBuilder& rhs) = delete; + MaterialBuilder& operator=(const MaterialBuilder& rhs) = delete; + + MaterialBuilder(MaterialBuilder&& rhs) noexcept = default; + MaterialBuilder& operator=(MaterialBuilder&& rhs) noexcept = default; + + static constexpr size_t MATERIAL_VARIABLES_COUNT = 4; + enum class Variable : uint8_t { + CUSTOM0, + CUSTOM1, + CUSTOM2, + CUSTOM3 + // when adding more variables, make sure to update MATERIAL_VARIABLES_COUNT + }; + + using MaterialDomain = filament::MaterialDomain; + using RefractionMode = filament::RefractionMode; + using RefractionType = filament::RefractionType; + using ReflectionMode = filament::ReflectionMode; + using VertexAttribute = filament::VertexAttribute; + + using ShaderQuality = filament::ShaderQuality; + using BlendingMode = filament::BlendingMode; + using Shading = filament::Shading; + using Interpolation = filament::Interpolation; + using VertexDomain = filament::VertexDomain; + using TransparencyMode = filament::TransparencyMode; + using SpecularAmbientOcclusion = filament::SpecularAmbientOcclusion; + + using AttributeType = filament::backend::UniformType; + using UniformType = filament::backend::UniformType; + using ConstantType = filament::backend::ConstantType; + using SamplerType = filament::backend::SamplerType; + using SubpassType = filament::backend::SubpassType; + using SamplerFormat = filament::backend::SamplerFormat; + using ParameterPrecision = filament::backend::Precision; + using Precision = filament::backend::Precision; + using CullingMode = filament::backend::CullingMode; + using FeatureLevel = filament::backend::FeatureLevel; + + enum class VariableQualifier : uint8_t { + OUT + }; + + enum class OutputTarget : uint8_t { + COLOR, + DEPTH + }; + + enum class OutputType : uint8_t { + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4 + }; + + struct PreprocessorDefine { + std::string name; + std::string value; + + PreprocessorDefine(std::string name, std::string value) : + name(std::move(name)), value(std::move(value)) {} + }; + using PreprocessorDefineList = std::vector; + + + MaterialBuilder& noSamplerValidation(bool enabled) noexcept; + + //! Enable generation of ESSL 1.0 code in FL0 materials. + MaterialBuilder& includeEssl1(bool enabled) noexcept; + + //! Set the name of this material. + MaterialBuilder& name(const char* name) noexcept; + + //! Set the file name of this material file. Used in error reporting. + MaterialBuilder& fileName(const char* name) noexcept; + + //! Set the shading model. + MaterialBuilder& shading(Shading shading) noexcept; + + //! Set the interpolation mode. + MaterialBuilder& interpolation(Interpolation interpolation) noexcept; + + //! Add a parameter (i.e., a uniform) to this material. + MaterialBuilder& parameter(const char* name, UniformType type, + ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept; + + //! Add a parameter array to this material. + MaterialBuilder& parameter(const char* name, size_t size, UniformType type, + ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept; + + //! Add a constant parameter to this material. + template + using is_supported_constant_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + template> + MaterialBuilder& constant(const char *name, ConstantType type, T defaultValue = 0); + + /** + * Add a sampler parameter to this material. + * + * When SamplerType::SAMPLER_EXTERNAL is specified, format and precision are ignored. + */ + MaterialBuilder& parameter(const char* name, SamplerType samplerType, + SamplerFormat format = SamplerFormat::FLOAT, + ParameterPrecision precision = ParameterPrecision::DEFAULT, + bool multisample = false) noexcept; + + MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept; + + //! Custom variables (all float4). + MaterialBuilder& variable(Variable v, const char* name) noexcept; + + /** + * Require a specified attribute. + * + * position is always required and normal depends on the shading model. + */ + MaterialBuilder& require(VertexAttribute attribute) noexcept; + + //! Specify the domain that this material will operate in. + MaterialBuilder& materialDomain(MaterialBuilder::MaterialDomain materialDomain) noexcept; + + /** + * Set the code content of this material. + * + * Surface Domain + * -------------- + * + * Materials in the SURFACE domain must declare a function: + * ~~~~~ + * void material(inout MaterialInputs material) { + * prepareMaterial(material); + * material.baseColor.rgb = float3(1.0, 0.0, 0.0); + * } + * ~~~~~ + * this function *must* call `prepareMaterial(material)` before it returns. + * + * Post-process Domain + * ------------------- + * + * Materials in the POST_PROCESS domain must declare a function: + * ~~~~~ + * void postProcess(inout PostProcessInputs postProcess) { + * postProcess.color = float4(1.0); + * } + * ~~~~~ + * + * @param code The source code of the material. + * @param line The line number offset of the material, where 0 is the first line. Used for error + * reporting + */ + MaterialBuilder& material(const char* code, size_t line = 0) noexcept; + + /** + * Set the callback used for resolving include directives. + * The default is no callback, which disallows all includes. + */ + MaterialBuilder& includeCallback(IncludeCallback callback) noexcept; + + /** + * Set the vertex code content of this material. + * + * Surface Domain + * -------------- + * + * Materials in the SURFACE domain must declare a function: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void materialVertex(inout MaterialVertexInputs material) { + * + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Post-process Domain + * ------------------- + * + * Materials in the POST_PROCESS domain must declare a function: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void postProcessVertex(inout PostProcessVertexInputs postProcess) { + * + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + * @param code The source code of the material. + * @param line The line number offset of the material, where 0 is the first line. Used for error + * reporting + */ + MaterialBuilder& materialVertex(const char* code, size_t line = 0) noexcept; + + + MaterialBuilder& quality(ShaderQuality quality) noexcept; + + MaterialBuilder& featureLevel(FeatureLevel featureLevel) noexcept; + + /** + * Set the blending mode for this material. When set to MASKED, alpha to coverage is turned on. + * You can override this behavior using alphaToCoverage(false). + */ + MaterialBuilder& blending(BlendingMode blending) noexcept; + + /** + * Set the blending mode of the post-lighting color for this material. + * Only OPAQUE, TRANSPARENT and ADD are supported, the default is TRANSPARENT. + * This setting requires the material property "postLightingColor" to be set. + */ + MaterialBuilder& postLightingBlending(BlendingMode blending) noexcept; + + //! Set the vertex domain for this material. + MaterialBuilder& vertexDomain(VertexDomain domain) noexcept; + + /** + * How triangles are culled by default (doesn't affect points or lines, BACK by default). + * Material instances can override this. + */ + MaterialBuilder& culling(CullingMode culling) noexcept; + + //! Enable / disable color-buffer write (enabled by default, material instances can override). + MaterialBuilder& colorWrite(bool enable) noexcept; + + //! Enable / disable depth-buffer write (enabled by default for opaque, disabled for others, material instances can override). + MaterialBuilder& depthWrite(bool enable) noexcept; + + //! Enable / disable depth based culling (enabled by default, material instances can override). + MaterialBuilder& depthCulling(bool enable) noexcept; + + //! Enable / disable instanced primitives (disabled by default). + MaterialBuilder& instanced(bool enable) noexcept; + + /** + * Double-sided materials don't cull faces, equivalent to culling(CullingMode::NONE). + * doubleSided() overrides culling() if called. + * When called with "false", this enables the capability for a run-time toggle. + */ + MaterialBuilder& doubleSided(bool doubleSided) noexcept; + + /** + * Any fragment with an alpha below this threshold is clipped (MASKED blending mode only). + * The mask threshold can also be controlled by using the float material parameter called + * `_maskThreshold`, or by calling + * @ref filament::MaterialInstance::setMaskThreshold "MaterialInstance::setMaskThreshold". + */ + MaterialBuilder& maskThreshold(float threshold) noexcept; + + /** + * Enables or disables alpha-to-coverage. When enabled, the coverage of a fragment is based + * on its alpha value. This parameter is only useful when MSAA is in use. Alpha to coverage + * is enabled automatically when the blend mode is set to MASKED; this behavior can be + * overridden by calling alphaToCoverage(false). + */ + MaterialBuilder& alphaToCoverage(bool enable) noexcept; + + //! The material output is multiplied by the shadowing factor (UNLIT model only). + MaterialBuilder& shadowMultiplier(bool shadowMultiplier) noexcept; + + //! This material casts transparent shadows. The blending mode must be TRANSPARENT or FADE. + MaterialBuilder& transparentShadow(bool transparentShadow) noexcept; + + /** + * Reduces specular aliasing for materials that have low roughness. Turning this feature on also + * helps preserve the shapes of specular highlights as an object moves away from the camera. + * When turned on, two float material parameters are added to control the effect: + * `_specularAAScreenSpaceVariance` and `_specularAAThreshold`. You can also use + * @ref filament::MaterialInstance::setSpecularAntiAliasingVariance + * "MaterialInstance::setSpecularAntiAliasingVariance" and + * @ref filament::MaterialInstance::setSpecularAntiAliasingThreshold + * "setSpecularAntiAliasingThreshold" + * + * Disabled by default. + */ + MaterialBuilder& specularAntiAliasing(bool specularAntiAliasing) noexcept; + + /** + * Sets the screen-space variance of the filter kernel used when applying specular + * anti-aliasing. The default value is set to 0.15. The specified value should be between 0 and + * 1 and will be clamped if necessary. + */ + MaterialBuilder& specularAntiAliasingVariance(float screenSpaceVariance) noexcept; + + /** + * Sets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. The default value is set to 0.2. The specified value should be between 0 and 1 + * and will be clamped if necessary. + */ + MaterialBuilder& specularAntiAliasingThreshold(float threshold) noexcept; + + /** + * Enables or disables the index of refraction (IoR) change caused by the clear coat layer when + * present. When the IoR changes, the base color is darkened. Disabling this feature preserves + * the base color as initially specified. + * + * Enabled by default. + */ + MaterialBuilder& clearCoatIorChange(bool clearCoatIorChange) noexcept; + + //! Enable / disable flipping of the Y coordinate of UV attributes, enabled by default. + MaterialBuilder& flipUV(bool flipUV) noexcept; + + //! Enable / disable multi-bounce ambient occlusion, disabled by default on mobile. + MaterialBuilder& multiBounceAmbientOcclusion(bool multiBounceAO) noexcept; + + //! Set the specular ambient occlusion technique. Disabled by default on mobile. + MaterialBuilder& specularAmbientOcclusion(SpecularAmbientOcclusion specularAO) noexcept; + + //! Specify the refraction + MaterialBuilder& refractionMode(RefractionMode refraction) noexcept; + + //! Specify the refraction type + MaterialBuilder& refractionType(RefractionType refractionType) noexcept; + + //! Specifies how reflections should be rendered (default is DEFAULT). + MaterialBuilder& reflectionMode(ReflectionMode mode) noexcept; + + //! Specifies how transparent objects should be rendered (default is DEFAULT). + MaterialBuilder& transparencyMode(TransparencyMode mode) noexcept; + + /** + * Enable / disable custom surface shading. Custom surface shading requires the LIT + * shading model. In addition, the following function must be defined in the fragment + * block: + * + * ~~~~~ + * vec3 surfaceShading(const MaterialInputs materialInputs, + * const ShadingData shadingData, const LightData lightData) { + * + * return vec3(1.0); // Compute surface shading with custom BRDF, etc. + * } + * ~~~~~ + * + * This function is invoked once per light. Please refer to the materials documentation + * for more information about the different parameters. + * + * @param customSurfaceShading Enables or disables custom surface shading + */ + MaterialBuilder& customSurfaceShading(bool customSurfaceShading) noexcept; + + /** + * Specifies desktop vs mobile; works in concert with TargetApi to determine the shader models + * (used to generate code) and final output representations (spirv and/or text). + */ + MaterialBuilder& platform(Platform platform) noexcept; + + /** + * Specifies OpenGL, Vulkan, or Metal. + * This can be called repeatedly to build for multiple APIs. + * Works in concert with Platform to determine the shader models (used to generate code) and + * final output representations (spirv and/or text). + * If linking against filamat_lite, only `OPENGL` is allowed. + */ + MaterialBuilder& targetApi(TargetApi targetApi) noexcept; + + /** + * Specifies the level of optimization to apply to the shaders (default is PERFORMANCE). + * If linking against filamat_lite, this _must_ be called with Optimization::NONE. + */ + MaterialBuilder& optimization(Optimization optimization) noexcept; + + // TODO: this is present here for matc's "--print" flag, but ideally does not belong inside + // MaterialBuilder. + //! If true, will output the generated GLSL shader code to stdout. + MaterialBuilder& printShaders(bool printShaders) noexcept; + + //! If true, will include debugging information in generated SPIRV. + MaterialBuilder& generateDebugInfo(bool generateDebugInfo) noexcept; + + //! Specifies a list of variants that should be filtered out during code generation. + MaterialBuilder& variantFilter(filament::UserVariantFilterMask variantFilter) noexcept; + + //! Adds a new preprocessor macro definition to the shader code. Can be called repeatedly. + MaterialBuilder& shaderDefine(const char* name, const char* value) noexcept; + + //! Add a new fragment shader output variable. Only valid for materials in the POST_PROCESS domain. + MaterialBuilder& output(VariableQualifier qualifier, OutputTarget target, Precision precision, + OutputType type, const char* name, int location = -1) noexcept; + + MaterialBuilder& enableFramebufferFetch() noexcept; + + MaterialBuilder& vertexDomainDeviceJittered(bool enabled) noexcept; + + /** + * Legacy morphing uses the data in the VertexAttribute slots (\c MORPH_POSITION_0, etc) and is + * limited to 4 morph targets. See filament::RenderableManager::Builder::morphing(). + */ + MaterialBuilder& useLegacyMorphing() noexcept; + + //! specify compute kernel group size + MaterialBuilder& groupSize(filament::math::uint3 groupSize) noexcept; + + /** + * Build the material. If you are using the Filament engine with this library, you should use + * the job system provided by Engine. + */ + Package build(utils::JobSystem& jobSystem) noexcept; + +public: + // The methods and types below are for internal use + /// @cond never + + /** + * Add a subpass parameter to this material. + */ + MaterialBuilder& subpass(SubpassType subpassType, + SamplerFormat format, ParameterPrecision precision, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, + SamplerFormat format, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, + ParameterPrecision precision, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, const char* name) noexcept; + + struct Parameter { + Parameter() noexcept: parameterType(INVALID) {} + + // Sampler + Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms) + : name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms) { } + + // Uniform + Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p) + : name(paramName), size(typeSize), uniformType(t), precision(p), parameterType(UNIFORM) { } + + // Subpass + Parameter(const char* paramName, SubpassType t, SamplerFormat f, ParameterPrecision p) + : name(paramName), size(1), precision(p), subpassType(t), format(f), parameterType(SUBPASS) { } + + utils::CString name; + size_t size; + UniformType uniformType; + ParameterPrecision precision; + SamplerType samplerType; + SubpassType subpassType; + SamplerFormat format; + bool multisample; + enum { + INVALID, + UNIFORM, + SAMPLER, + SUBPASS + } parameterType; + + bool isSampler() const { return parameterType == SAMPLER; } + bool isUniform() const { return parameterType == UNIFORM; } + bool isSubpass() const { return parameterType == SUBPASS; } + }; + + struct Output { + Output() noexcept = default; + Output(const char* outputName, VariableQualifier qualifier, OutputTarget target, + Precision precision, OutputType type, int location) noexcept + : name(outputName), qualifier(qualifier), target(target), precision(precision), + type(type), location(location) { } + + utils::CString name; + VariableQualifier qualifier; + OutputTarget target; + Precision precision; + OutputType type; + int location; + }; + + struct Constant { + utils::CString name; + ConstantType type; + union { + int32_t i; + float f; + bool b; + } defaultValue; + }; + + static constexpr size_t MATERIAL_PROPERTIES_COUNT = filament::MATERIAL_PROPERTIES_COUNT; + using Property = filament::Property; + + using PropertyList = bool[MATERIAL_PROPERTIES_COUNT]; + using VariableList = utils::CString[MATERIAL_VARIABLES_COUNT]; + using OutputList = std::vector; + + static constexpr size_t MAX_COLOR_OUTPUT = filament::backend::MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; + static constexpr size_t MAX_DEPTH_OUTPUT = 1; + static_assert(MAX_COLOR_OUTPUT == 8, + "When updating MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT, manually update post_process_inputs.fs" + " and post_process.fs"); + + // Preview the first shader generated by the given CodeGenParams. + // This is used to run Static Code Analysis before generating a package. + std::string peek(filament::backend::ShaderStage type, + const CodeGenParams& params, const PropertyList& properties) noexcept; + + // Returns true if any of the parameter samplers matches the specified type. + bool hasSamplerType(SamplerType samplerType) const noexcept; + + static constexpr size_t MAX_PARAMETERS_COUNT = 48; + static constexpr size_t MAX_SUBPASS_COUNT = 1; + static constexpr size_t MAX_BUFFERS_COUNT = 4; + using ParameterList = Parameter[MAX_PARAMETERS_COUNT]; + using SubpassList = Parameter[MAX_SUBPASS_COUNT]; + using BufferList = std::vector>; + using ConstantList = std::vector; + + // returns the number of parameters declared in this material + uint8_t getParameterCount() const noexcept { return mParameterCount; } + + // returns a list of at least getParameterCount() parameters + const ParameterList& getParameters() const noexcept { return mParameters; } + + // returns the number of parameters declared in this material + uint8_t getSubpassCount() const noexcept { return mSubpassCount; } + + // returns a list of at least getParameterCount() parameters + const SubpassList& getSubPasses() const noexcept { return mSubpasses; } + + filament::UserVariantFilterMask getVariantFilter() const { return mVariantFilter; } + + FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; } + /// @endcond + + struct Attribute { + std::string_view name; + AttributeType type; + MaterialBuilder::VertexAttribute location; + std::string getAttributeName() const noexcept { + return "mesh_" + std::string{ name }; + } + std::string getDefineName() const noexcept { + std::string uppercase{ name }; + transform(uppercase.cbegin(), uppercase.cend(), uppercase.begin(), ::toupper); + return "HAS_ATTRIBUTE_" + uppercase; + } + }; + + using AttributeDatabase = std::array; + + static inline AttributeDatabase const& getAttributeDatabase() noexcept { + return sAttributeDatabase; + } + +private: + static const AttributeDatabase sAttributeDatabase; + + void prepareToBuild(MaterialInfo& info) noexcept; + + // Return true if the shader is syntactically and semantically valid. + // This method finds all the properties defined in the fragment and + // vertex shaders of the material. + bool findAllProperties(CodeGenParams const& semanticCodeGenParams) noexcept; + + // Multiple calls to findProperties accumulate the property sets across fragment + // and vertex shaders in mProperties. + bool findProperties(filament::backend::ShaderStage type, + MaterialBuilder::PropertyList& allProperties, + CodeGenParams const& semanticCodeGenParams) noexcept; + + bool runSemanticAnalysis(MaterialInfo* inOutInfo, + CodeGenParams const& semanticCodeGenParams) noexcept; + + bool checkLiteRequirements() noexcept; + + bool checkMaterialLevelFeatures(MaterialInfo const& info) const noexcept; + + void writeCommonChunks(ChunkContainer& container, MaterialInfo& info) const noexcept; + void writeSurfaceChunks(ChunkContainer& container) const noexcept; + + bool generateShaders( + utils::JobSystem& jobSystem, + const std::vector& variants, ChunkContainer& container, + const MaterialInfo& info) const noexcept; + + bool hasCustomVaryings() const noexcept; + bool needsStandardDepthProgram() const noexcept; + + bool isLit() const noexcept { return mShading != filament::Shading::UNLIT; } + + utils::CString mMaterialName; + utils::CString mFileName; + + class ShaderCode { + public: + void setLineOffset(size_t offset) noexcept { mLineOffset = offset; } + void setUnresolved(const utils::CString& code) noexcept { + mIncludesResolved = false; + mCode = code; + } + + // Resolve all the #include directives, returns true if successful. + bool resolveIncludes(IncludeCallback callback, const utils::CString& fileName) noexcept; + + const utils::CString& getResolved() const noexcept { + assert(mIncludesResolved); + return mCode; + } + + size_t getLineOffset() const noexcept { return mLineOffset; } + + private: + utils::CString mCode; + size_t mLineOffset = 0; + bool mIncludesResolved = false; + }; + + ShaderCode mMaterialFragmentCode; + ShaderCode mMaterialVertexCode; + + IncludeCallback mIncludeCallback = nullptr; + + PropertyList mProperties; + ParameterList mParameters; + ConstantList mConstants; + SubpassList mSubpasses; + VariableList mVariables; + OutputList mOutputs; + BufferList mBuffers; + + ShaderQuality mShaderQuality = ShaderQuality::DEFAULT; + FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1; + BlendingMode mBlendingMode = BlendingMode::OPAQUE; + BlendingMode mPostLightingBlendingMode = BlendingMode::TRANSPARENT; + CullingMode mCullingMode = CullingMode::BACK; + Shading mShading = Shading::LIT; + MaterialDomain mMaterialDomain = MaterialDomain::SURFACE; + RefractionMode mRefractionMode = RefractionMode::NONE; + RefractionType mRefractionType = RefractionType::SOLID; + ReflectionMode mReflectionMode = ReflectionMode::DEFAULT; + Interpolation mInterpolation = Interpolation::SMOOTH; + VertexDomain mVertexDomain = VertexDomain::OBJECT; + TransparencyMode mTransparencyMode = TransparencyMode::DEFAULT; + + filament::AttributeBitset mRequiredAttributes; + + float mMaskThreshold = 0.4f; + float mSpecularAntiAliasingVariance = 0.15f; + float mSpecularAntiAliasingThreshold = 0.2f; + + filament::math::uint3 mGroupSize = { 1, 1, 1 }; + + bool mShadowMultiplier = false; + bool mTransparentShadow = false; + + uint8_t mParameterCount = 0; + uint8_t mSubpassCount = 0; + + bool mDoubleSided = false; + bool mDoubleSidedCapability = false; + bool mColorWrite = true; + bool mDepthTest = true; + bool mInstanced = false; + bool mDepthWrite = true; + bool mDepthWriteSet = false; + bool mAlphaToCoverage = false; + bool mAlphaToCoverageSet = false; + + bool mSpecularAntiAliasing = false; + bool mClearCoatIorChange = true; + + bool mFlipUV = true; + + bool mMultiBounceAO = false; + bool mMultiBounceAOSet = false; + + SpecularAmbientOcclusion mSpecularAO = SpecularAmbientOcclusion::NONE; + bool mSpecularAOSet = false; + + bool mCustomSurfaceShading = false; + + bool mEnableFramebufferFetch = false; + + bool mVertexDomainDeviceJittered = false; + + bool mUseLegacyMorphing = false; + + PreprocessorDefineList mDefines; + + filament::UserVariantFilterMask mVariantFilter = {}; + + bool mNoSamplerValidation = false; +}; + +} // namespace filamat + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif diff --git a/package/android/libs/filament/include/filamat/Package.h b/package/android/libs/filament/include/filamat/Package.h new file mode 100644 index 00000000..93e74a58 --- /dev/null +++ b/package/android/libs/filament/include/filamat/Package.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMAT_PACKAGE_H +#define TNT_FILAMAT_PACKAGE_H + +#include +#include +#include + +#include +#include + +#include + +namespace filamat { + +class UTILS_PUBLIC Package { +public: + Package() = default; + + // Regular constructor + explicit Package(size_t size) : mSize(size) { + mPayload = new uint8_t[size]; + } + + Package(const void* src, size_t size) : Package(size) { + memcpy(mPayload, src, size); + } + + // Move Constructor + Package(Package&& other) noexcept : mPayload(other.mPayload), mSize(other.mSize), + mValid(other.mValid) { + other.mPayload = nullptr; + other.mSize = 0; + other.mValid = false; + } + + // Move assignment + Package& operator=(Package&& other) noexcept { + std::swap(mPayload, other.mPayload); + std::swap(mSize, other.mSize); + std::swap(mValid, other.mValid); + return *this; + } + + // Copy assignment operator disallowed. + Package& operator=(const Package& other) = delete; + + // Copy constructor disallowed. + Package(const Package& other) = delete; + + ~Package() { + delete[] mPayload; + } + + uint8_t* getData() const noexcept { + return mPayload; + } + + size_t getSize() const noexcept { + return mSize; + } + + uint8_t* getEnd() const noexcept { + return mPayload + mSize; + } + + void setValid(bool valid) noexcept { + mValid = valid; + } + + bool isValid() const noexcept { + return mValid; + } + + static Package invalidPackage() { + Package package(0); + package.setValid(false); + return package; + } + +private: + uint8_t* mPayload = nullptr; + size_t mSize = 0; + bool mValid = true; +}; + +} // namespace filamat +#endif diff --git a/package/android/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h b/package/android/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h new file mode 100644 index 00000000..815ff613 --- /dev/null +++ b/package/android/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_IBL_PREFILTER_IBLPREFILTER_H +#define TNT_IBL_PREFILTER_IBLPREFILTER_H + +#include +#include + +#include + +namespace filament { +class Engine; +class View; +class Scene; +class Renderer; +class Material; +class MaterialInstance; +class VertexBuffer; +class IndexBuffer; +class Camera; +class Texture; +} // namespace filament + +/** + * IBLPrefilterContext creates and initializes GPU state common to all environment map filters + * supported. Typically, only one instance per filament Engine of this object needs to exist. + * + * Usage Example: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * IBLPrefilterContext context(engine); + * IBLPrefilterContext::SpecularFilter filter(context); + * Texture* texture = filter(environment_cubemap); + * + * IndirectLight* indirectLight = IndirectLight::Builder() + * .reflections(texture) + * .build(engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC IBLPrefilterContext { +public: + + enum class Kernel : uint8_t { + D_GGX, // Trowbridge-reitz distribution + }; + + /** + * Creates an IBLPrefilter context. + * @param engine filament engine to use + */ + explicit IBLPrefilterContext(filament::Engine& engine); + + /** + * Destroys all GPU resources created during initialization. + */ + ~IBLPrefilterContext() noexcept; + + // not copyable + IBLPrefilterContext(IBLPrefilterContext const&) = delete; + IBLPrefilterContext& operator=(IBLPrefilterContext const&) = delete; + + // movable + IBLPrefilterContext(IBLPrefilterContext&& rhs) noexcept; + IBLPrefilterContext& operator=(IBLPrefilterContext&& rhs) noexcept; + + // ------------------------------------------------------------------------------------------- + + /** + * EquirectangularToCubemap is use to convert an equirectangluar image to a cubemap. + */ + class EquirectangularToCubemap { + public: + /** + * Creates a EquirectangularToCubemap processor. + * @param context IBLPrefilterContext to use + */ + explicit EquirectangularToCubemap(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~EquirectangularToCubemap() noexcept; + + EquirectangularToCubemap(EquirectangularToCubemap const&) = delete; + EquirectangularToCubemap& operator=(EquirectangularToCubemap const&) = delete; + EquirectangularToCubemap(EquirectangularToCubemap&& rhs) noexcept; + EquirectangularToCubemap& operator=(EquirectangularToCubemap&& rhs) noexcept; + + /** + * Converts an equirectangular image to a cubemap. + * @param equirectangular Texture to convert to a cubemap. + * - Can't be null. + * - Must be a 2d texture + * - Must have equirectangular geometry, that is width == 2*height. + * - Must be allocated with all mip levels. + * - Must be SAMPLEABLE + * @param outCubemap Output cubemap. If null the texture is automatically created + * with default parameters (size of 256 with 9 levels). + * - Must be a cubemap + * - Must have SAMPLEABLE and COLOR_ATTACHMENT usage bits + * @return returns outCubemap + */ + filament::Texture* operator()( + filament::Texture const* equirectangular, + filament::Texture* outCubemap = nullptr); + + private: + IBLPrefilterContext& mContext; + filament::Material* mEquirectMaterial = nullptr; + }; + + /** + * IrradianceFilter is a GPU based implementation of the diffuse probe pre-integration filter. + * An instance of IrradianceFilter is needed per filter configuration. A filter configuration + * contains the filter's kernel and sample count. + */ + class IrradianceFilter { + public: + using Kernel = Kernel; + + /** + * Filter configuration. + */ + struct Config { + uint16_t sampleCount = 1024u; //!< filter sample count (max 2048) + Kernel kernel = Kernel::D_GGX; //!< filter kernel + }; + + /** + * Filtering options for the current environment. + */ + struct Options { + float hdrLinear = 1024.0f; //!< no HDR compression up to this value + float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax + float lodOffset = 2.0f; //!< Good values are 2.0 or 3.0. Higher values help with heavily HDR inputs. + bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps + }; + + /** + * Creates a IrradianceFilter processor. + * @param context IBLPrefilterContext to use + * @param config Configuration of the filter + */ + IrradianceFilter(IBLPrefilterContext& context, Config config); + + /** + * Creates a filter with the default configuration. + * @param context IBLPrefilterContext to use + */ + explicit IrradianceFilter(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~IrradianceFilter() noexcept; + + IrradianceFilter(IrradianceFilter const&) = delete; + IrradianceFilter& operator=(IrradianceFilter const&) = delete; + IrradianceFilter(IrradianceFilter&& rhs) noexcept; + IrradianceFilter& operator=(IrradianceFilter&& rhs) noexcept; + + /** + * Generates an irradiance cubemap. Mipmaps are not generated even if present. + * @param options Options for this environment + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outIrradianceTexture Output irradiance texture or, if null, it is + * automatically created with some default parameters. + * outIrradianceTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages. + * + * @return returns outIrradianceTexture + */ + filament::Texture* operator()(Options options, + filament::Texture const* environmentCubemap, + filament::Texture* outIrradianceTexture = nullptr); + + /** + * Generates a prefiltered cubemap. + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outIrradianceTexture Output irradiance texture or, if null, it is + * automatically created with some default parameters. + * outIrradianceTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages. + * + * @return returns outReflectionsTexture + */ + filament::Texture* operator()( + filament::Texture const* environmentCubemap, + filament::Texture* outIrradianceTexture = nullptr); + + private: + filament::Texture* createIrradianceTexture(); + IBLPrefilterContext& mContext; + filament::Material* mKernelMaterial = nullptr; + filament::Texture* mKernelTexture = nullptr; + uint32_t mSampleCount = 0u; + }; + + /** + * SpecularFilter is a GPU based implementation of the specular probe pre-integration filter. + * An instance of SpecularFilter is needed per filter configuration. A filter configuration + * contains the filter's kernel and sample count. + */ + class SpecularFilter { + public: + using Kernel = Kernel; + + /** + * Filter configuration. + */ + struct Config { + uint16_t sampleCount = 1024u; //!< filter sample count (max 2048) + uint8_t levelCount = 5u; //!< number of roughness levels + Kernel kernel = Kernel::D_GGX; //!< filter kernel + }; + + /** + * Filtering options for the current environment. + */ + struct Options { + float hdrLinear = 1024.0f; //!< no HDR compression up to this value + float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax + float lodOffset = 1.0f; //!< Good values are 1.0 or 2.0. Higher values help with heavily HDR inputs. + bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps + }; + + /** + * Creates a SpecularFilter processor. + * @param context IBLPrefilterContext to use + * @param config Configuration of the filter + */ + SpecularFilter(IBLPrefilterContext& context, Config config); + + /** + * Creates a filter with the default configuration. + * @param context IBLPrefilterContext to use + */ + explicit SpecularFilter(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~SpecularFilter() noexcept; + + SpecularFilter(SpecularFilter const&) = delete; + SpecularFilter& operator=(SpecularFilter const&) = delete; + SpecularFilter(SpecularFilter&& rhs) noexcept; + SpecularFilter& operator=(SpecularFilter&& rhs) noexcept; + + /** + * Generates a prefiltered cubemap. + * @param options Options for this environment + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outReflectionsTexture Output prefiltered texture or, if null, it is + * automatically created with some default parameters. + * outReflectionsTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages and at + * least the same number of levels than requested by Config. + * @return returns outReflectionsTexture + */ + filament::Texture* operator()(Options options, + filament::Texture const* environmentCubemap, + filament::Texture* outReflectionsTexture = nullptr); + + /** + * Generates a prefiltered cubemap. + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. All mipmap levels will be overwritten. + * @param outReflectionsTexture Output prefiltered texture or, if null, it is + * automatically created with some default parameters. + * outReflectionsTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages and at + * least the same number of levels than requested by Config. + * @return returns outReflectionsTexture + */ + filament::Texture* operator()( + filament::Texture const* environmentCubemap, + filament::Texture* outReflectionsTexture = nullptr); + + // TODO: option for progressive filtering + + // TODO: add a callback for when the processing is done? + + private: + filament::Texture* createReflectionsTexture(); + IBLPrefilterContext& mContext; + filament::Material* mKernelMaterial = nullptr; + filament::Texture* mKernelTexture = nullptr; + uint32_t mSampleCount = 0u; + uint8_t mLevelCount = 1u; + }; + +private: + friend class Filter; + filament::Engine& mEngine; + filament::Renderer* mRenderer{}; + filament::Scene* mScene{}; + filament::VertexBuffer* mVertexBuffer{}; + filament::IndexBuffer* mIndexBuffer{}; + filament::Camera* mCamera{}; + utils::Entity mFullScreenQuadEntity{}; + utils::Entity mCameraEntity{}; + filament::View* mView{}; + filament::Material* mIntegrationMaterial{}; + filament::Material* mIrradianceIntegrationMaterial{}; +}; + +#endif //TNT_IBL_PREFILTER_IBLPREFILTER_H diff --git a/package/android/libs/filament/include/filament/Box.h b/package/android/libs/filament/include/filament/Box.h new file mode 100644 index 00000000..da6638da --- /dev/null +++ b/package/android/libs/filament/include/filament/Box.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BOX_H +#define TNT_FILAMENT_BOX_H + +#include + +#include +#include +#include +#include + +#include + +#include + +namespace filament { + +/** + * An axis aligned 3D box represented by its center and half-extent. + */ +class UTILS_PUBLIC Box { +public: + /** Center of the 3D box */ + math::float3 center = {}; + + /** Half extent from the center on all 3 axis */ + math::float3 halfExtent = {}; + + /** + * Whether the box is empty, i.e.: it's volume is null. + * @return true if the volume of the box is null + */ + constexpr bool isEmpty() const noexcept { + return length2(halfExtent) == 0; + } + + /** + * Computes the lowest coordinates corner of the box. + * @return center - halfExtent + */ + constexpr math::float3 getMin() const noexcept { + return center - halfExtent; + } + + /** + * Computes the largest coordinates corner of the box. + * @return center + halfExtent + */ + constexpr math::float3 getMax() const noexcept { + return center + halfExtent; + } + + /** + * Initializes the 3D box from its min / max coordinates on each axis + * @param min lowest coordinates corner of the box + * @param max largest coordinates corner of the box + * @return This bounding box + */ + Box& set(const math::float3& min, const math::float3& max) noexcept { + // float3 ctor needed for Visual Studio + center = (max + min) * math::float3(0.5f); + halfExtent = (max - min) * math::float3(0.5f); + return *this; + } + + /** + * Computes the bounding box of the union of two boxes + * @param box The box to be combined with + * @return The bounding box of the union of *this and box + */ + Box& unionSelf(const Box& box) noexcept { + set(min(getMin(), box.getMin()), max(getMax(), box.getMax())); + return *this; + } + + /** + * Translates the box *to* a given center position + * @param tr position to translate the box to + * @return A box centered in \p tr with the same extent than *this + */ + constexpr Box translateTo(const math::float3& tr) const noexcept { + return Box{ tr, halfExtent }; + } + + /** + * Computes the smallest bounding sphere of the box. + * @return The smallest sphere defined by its center (.xyz) and radius (.w) that contains *this + */ + math::float4 getBoundingSphere() const noexcept { + return { center, length(halfExtent) }; + } + + /** + * Transform a Box by a linear transform and a translation. + * + * @param m a 3x3 matrix, the linear transform + * @param t a float3, the translation + * @param box the box to transform + * @return the bounding box of the transformed box + */ + static Box transform(const math::mat3f& m, math::float3 const& t, const Box& box) noexcept { + return { m * box.center + t, abs(m) * box.halfExtent }; + } + + /** + * @deprecated Use transform() instead + * @see transform() + */ + friend Box rigidTransform(Box const& box, const math::mat4f& m) noexcept { + return transform(m.upperLeft(), m[3].xyz, box); + } +}; + +/** + * An axis aligned box represented by its min and max coordinates + */ +struct UTILS_PUBLIC Aabb { + + /** min coordinates */ + math::float3 min = FLT_MAX; + + /** max coordinates */ + math::float3 max = -FLT_MAX; + + /** + * Computes the center of the box. + * @return (max + min)/2 + */ + math::float3 center() const noexcept { + // float3 ctor needed for Visual Studio + return (max + min) * math::float3(0.5f); + } + + /** + * Computes the half-extent of the box. + * @return (max - min)/2 + */ + math::float3 extent() const noexcept { + // float3 ctor needed for Visual Studio + return (max - min) * math::float3(0.5f); + } + + /** + * Whether the box is empty, i.e.: it's volume is null or negative. + * @return true if min >= max, i.e: the volume of the box is null or negative + */ + bool isEmpty() const noexcept { + return any(greaterThanEqual(min, max)); + } + + struct Corners { + using value_type = math::float3; + value_type const* begin() const { return vertices; } + value_type const* end() const { return vertices + 8; } + value_type * begin() { return vertices; } + value_type * end() { return vertices + 8; } + value_type const* data() const { return vertices; } + value_type * data() { return vertices; } + size_t size() const { return 8; } + value_type const& operator[](size_t i) const noexcept { return vertices[i]; } + value_type& operator[](size_t i) noexcept { return vertices[i]; } + value_type vertices[8]; + }; + + /** + * Returns the 8 corner vertices of the AABB. + */ + Corners getCorners() const { + return Aabb::Corners{ .vertices = { + { min.x, min.y, min.z }, + { max.x, min.y, min.z }, + { min.x, max.y, min.z }, + { max.x, max.y, min.z }, + { min.x, min.y, max.z }, + { max.x, min.y, max.z }, + { min.x, max.y, max.z }, + { max.x, max.y, max.z }, + }}; + } + + /** + * Returns whether the box contains a given point. + * + * @param p the point to test + * @return the maximum signed distance to the box. Negative if p is in the box + */ + float contains(math::float3 p) const noexcept { + // we don't use std::max to avoid a dependency on + auto const maximum = [](auto a, auto b) { return a > b ? a : b; }; + float d = min.x - p.x; + d = maximum(d, min.y - p.y); + d = maximum(d, min.z - p.z); + d = maximum(d, p.x - max.x); + d = maximum(d, p.y - max.y); + d = maximum(d, p.z - max.z); + return d; + } + + /** + * Applies an affine transformation to the AABB. + * + * @param m the 3x3 transformation to apply + * @param t the translation + * @return the transformed box + */ + static Aabb transform(const math::mat3f& m, math::float3 const& t, const Aabb& box) noexcept { + // Fast AABB transformation per Jim Arvo in Graphics Gems (1990). + Aabb result{ t, t }; + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + const float a = m[col][row] * box.min[col]; + const float b = m[col][row] * box.max[col]; + result.min[row] += a < b ? a : b; + result.max[row] += a < b ? b : a; + } + } + return result; + } + + /** + * @deprecated Use transform() instead + * @see transform() + */ + Aabb transform(const math::mat4f& m) const noexcept { + return transform(m.upperLeft(), m[3].xyz, *this); + } +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BOX_H diff --git a/package/android/libs/filament/include/filament/BufferObject.h b/package/android/libs/filament/include/filament/BufferObject.h new file mode 100644 index 00000000..74a4b1ff --- /dev/null +++ b/package/android/libs/filament/include/filament/BufferObject.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! \file + +#ifndef TNT_FILAMENT_BUFFEROBJECT_H +#define TNT_FILAMENT_BUFFEROBJECT_H + +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FBufferObject; + +class Engine; + +/** + * A generic GPU buffer containing data. + * + * Usage of this BufferObject is optional. For simple use cases it is not necessary. It is useful + * only when you need to share data between multiple VertexBuffer instances. It also allows you to + * efficiently swap-out the buffers in VertexBuffer. + * + * NOTE: For now this is only used for vertex data, but in the future we may use it for other things + * (e.g. compute). + * + * @see VertexBuffer + */ +class UTILS_PUBLIC BufferObject : public FilamentAPI { + struct BuilderDetails; + +public: + using BufferDescriptor = backend::BufferDescriptor; + using BindingType = backend::BufferObjectBinding; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the buffer in bytes. + * @param byteCount Maximum number of bytes the BufferObject can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& size(uint32_t byteCount) noexcept; + + /** + * The binding type for this buffer object. (defaults to VERTEX) + * @param BindingType Distinguishes between SSBO, VBO, etc. For now this must be VERTEX. + * @return A reference to this Builder for chaining calls. + */ + Builder& bindingType(BindingType bindingType) noexcept; + + /** + * Creates the BufferObject and returns a pointer to it. After creation, the buffer + * object is uninitialized. Use BufferObject::setBuffer() to initialize it. + * + * @param engine Reference to the filament::Engine to associate this BufferObject with. + * + * @return pointer to the newly created object + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see IndexBuffer::setBuffer + */ + BufferObject* UTILS_NONNULL build(Engine& engine); + private: + friend class FBufferObject; + }; + + /** + * Asynchronously copy-initializes a region of this BufferObject from the data provided. + * + * @param engine Reference to the filament::Engine associated with this BufferObject. + * @param buffer A BufferDescriptor representing the data used to initialize the BufferObject. + * @param byteOffset Offset in bytes into the BufferObject + */ + void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0); + + /** + * Returns the size of this BufferObject in elements. + * @return The maximum capacity of the BufferObject. + */ + size_t getByteCount() const noexcept; + +protected: + // prevent heap allocation + ~BufferObject() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BUFFEROBJECT_H diff --git a/package/android/libs/filament/include/filament/Camera.h b/package/android/libs/filament/include/filament/Camera.h new file mode 100644 index 00000000..74f34af0 --- /dev/null +++ b/package/android/libs/filament/include/filament/Camera.h @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_CAMERA_H +#define TNT_FILAMENT_CAMERA_H + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament { + +/** + * Camera represents the eye(s) through which the scene is viewed. + * + * A Camera has a position and orientation and controls the projection and exposure parameters. + * + * For stereoscopic rendering, a Camera maintains two separate "eyes": Eye 0 and Eye 1. These are + * arbitrary and don't necessarily need to correspond to "left" and "right". + * + * Creation and destruction + * ======================== + * + * In Filament, Camera is a component that must be associated with an entity. To do so, + * use Engine::createCamera(Entity). A Camera component is destroyed using + * Engine::destroyCameraComponent(Entity). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * utils::Entity myCameraEntity = utils::EntityManager::get().create(); + * filament::Camera* myCamera = engine->createCamera(myCameraEntity); + * myCamera->setProjection(45, 16.0/9.0, 0.1, 1.0); + * myCamera->lookAt({0, 1.60, 1}, {0, 0, 0}); + * engine->destroyCameraComponent(myCamera); + * ~~~~~~~~~~~ + * + * + * Coordinate system + * ================= + * + * The camera coordinate system defines the *view space*. The camera points towards its -z axis + * and is oriented such that its top side is in the direction of +y, and its right side in the + * direction of +x. + * + * @note + * Since the *near* and *far* planes are defined by the distance from the camera, + * their respective coordinates are -\p distance(near) and -\p distance(far). + * + * Clipping planes + * =============== + * + * The camera defines six *clipping planes* which together create a *clipping volume*. The + * geometry outside this volume is clipped. + * + * The clipping volume can either be a box or a frustum depending on which projection is used, + * respectively Projection.ORTHO or Projection.PERSPECTIVE. The six planes are specified either + * directly or indirectly using setProjection(). + * + * The six planes are: + * - left + * - right + * - bottom + * - top + * - near + * - far + * + * @note + * To increase the depth-buffer precision, the *far* clipping plane is always assumed to be at + * infinity for rendering. That is, it is not used to clip geometry during rendering. + * However, it is used during the culling phase (objects entirely behind the *far* + * plane are culled). + * + * + * Choosing the *near* plane distance + * ================================== + * + * The *near* plane distance greatly affects the depth-buffer resolution. + * + * Example: Precision at 1m, 10m, 100m and 1Km for various near distances assuming a 32-bit float + * depth-buffer: + * + * near (m) | 1 m | 10 m | 100 m | 1 Km + * -----------:|:------:|:-------:|:--------:|:--------: + * 0.001 | 7.2e-5 | 0.0043 | 0.4624 | 48.58 + * 0.01 | 6.9e-6 | 0.0001 | 0.0430 | 4.62 + * 0.1 | 3.6e-7 | 7.0e-5 | 0.0072 | 0.43 + * 1.0 | 0 | 3.8e-6 | 0.0007 | 0.07 + * + * As can be seen in the table above, the depth-buffer precision drops rapidly with the + * distance to the camera. + * + * Make sure to pick the highest *near* plane distance possible. + * + * On Vulkan and Metal platforms (or OpenGL platforms supporting either EXT_clip_control or + * ARB_clip_control extensions), the depth-buffer precision is much less dependent on the *near* + * plane value: + * + * near (m) | 1 m | 10 m | 100 m | 1 Km + * -----------:|:------:|:-------:|:--------:|:--------: + * 0.001 | 1.2e-7 | 9.5e-7 | 7.6e-6 | 6.1e-5 + * 0.01 | 1.2e-7 | 9.5e-7 | 7.6e-6 | 6.1e-5 + * 0.1 | 5.9e-8 | 9.5e-7 | 1.5e-5 | 1.2e-4 + * 1.0 | 0 | 9.5e-7 | 7.6e-6 | 1.8e-4 + * + * + * Choosing the *far* plane distance + * ================================= + * + * The far plane distance is always set internally to infinity for rendering, however it is used for + * culling and shadowing calculations. It is important to keep a reasonable ratio between + * the near and far plane distances. Typically a ratio in the range 1:100 to 1:100000 is + * commanded. Larger values may causes rendering artifacts or trigger assertions in debug builds. + * + * + * Exposure + * ======== + * + * The Camera is also used to set the scene's exposure, just like with a real camera. The lights + * intensity and the Camera exposure interact to produce the final scene's brightness. + * + * + * Stereoscopic rendering + * ====================== + * + * The Camera's transform (as set by setModelMatrix or via TransformManager) defines a "head" space, + * which typically corresponds to the location of the viewer's head. Each eye's transform is set + * relative to this head space by setEyeModelMatrix. + * + * Each eye also maintains its own projection matrix. These can be set with setCustomEyeProjection. + * Care must be taken to correctly set the projectionForCulling matrix, as well as its corresponding + * near and far values. The projectionForCulling matrix must define a frustum (in head space) that + * bounds the frustums of both eyes. Alternatively, culling may be disabled with + * View::setFrustumCullingEnabled. + * + * \see Frustum, View + */ +class UTILS_PUBLIC Camera : public FilamentAPI { +public: + //! Denotes the projection type used by this camera. \see setProjection + enum class Projection : int { + PERSPECTIVE, //!< perspective projection, objects get smaller as they are farther + ORTHO //!< orthonormal projection, preserves distances + }; + + //! Denotes a field-of-view direction. \see setProjection + enum class Fov : int { + VERTICAL, //!< the field-of-view angle is defined on the vertical axis + HORIZONTAL //!< the field-of-view angle is defined on the horizontal axis + }; + + /** Returns the projection matrix from the field-of-view. + * + * @param fovInDegrees full field-of-view in degrees. 0 < \p fov < 180. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + * @param direction direction of the \p fovInDegrees parameter. + * + * @see Fov. + */ + static math::mat4 projection(Fov direction, double fovInDegrees, + double aspect, double near, double far = INFINITY); + + /** Returns the projection matrix from the focal length. + * + * @param focalLengthInMillimeters lens's focal length in millimeters. \p focalLength > 0. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + static math::mat4 projection(double focalLengthInMillimeters, + double aspect, double near, double far = INFINITY); + + + /** Sets the projection matrix from a frustum defined by six planes. + * + * @param projection type of #Projection to use. + * + * @param left distance in world units from the camera to the left plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param right distance in world units from the camera to the right plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param bottom distance in world units from the camera to the bottom plane, + * at the near plane. + * Precondition: \p bottom != \p top. + * + * @param top distance in world units from the camera to the top plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param near distance in world units from the camera to the near plane. The near plane's + * position in view space is z = -\p near. + * Precondition: \p near > 0 for PROJECTION::PERSPECTIVE or + * \p near != far for PROJECTION::ORTHO + * + * @param far distance in world units from the camera to the far plane. The far plane's + * position in view space is z = -\p far. + * Precondition: \p far > near for PROJECTION::PERSPECTIVE or + * \p far != near for PROJECTION::ORTHO + * + * @see Projection, Frustum + */ + void setProjection(Projection projection, + double left, double right, + double bottom, double top, + double near, double far); + + + /** Utility to set the projection matrix from the field-of-view. + * + * @param fovInDegrees full field-of-view in degrees. 0 < \p fov < 180. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + * @param direction direction of the \p fovInDegrees parameter. + * + * @see Fov. + */ + void setProjection(double fovInDegrees, double aspect, double near, double far, + Fov direction = Fov::VERTICAL); + + /** Utility to set the projection matrix from the focal length. + * + * @param focalLengthInMillimeters lens's focal length in millimeters. \p focalLength > 0. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setLensProjection(double focalLengthInMillimeters, + double aspect, double near, double far); + + + /** Sets a custom projection matrix. + * + * The projection matrix must define an NDC system that must match the OpenGL convention, + * that is all 3 axis are mapped to [-1, 1]. + * + * @param projection custom projection matrix used for rendering and culling + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setCustomProjection(math::mat4 const& projection, double near, double far) noexcept; + + /** Sets the projection matrix. + * + * The projection matrices must define an NDC system that must match the OpenGL convention, + * that is all 3 axis are mapped to [-1, 1]. + * + * @param projection custom projection matrix used for rendering + * @param projectionForCulling custom projection matrix used for culling + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setCustomProjection(math::mat4 const& projection, math::mat4 const& projectionForCulling, + double near, double far) noexcept; + + /** Sets a custom projection matrix for each eye. + * + * The projectionForCulling, near, and far parameters establish a "culling frustum" which must + * encompass anything any eye can see. All projection matrices must be set simultaneously. The + * number of stereoscopic eyes is controlled by the stereoscopicEyeCount setting inside of + * Engine::Config. + * + * @param projection an array of projection matrices, only the first config.stereoscopicEyeCount + * are read + * @param count size of the projection matrix array to set, must be + * >= config.stereoscopicEyeCount + * @param projectionForCulling custom projection matrix for culling, must encompass both eyes + * @param near distance in world units from the camera to the culling near plane. \p near > 0. + * @param far distance in world units from the camera to the culling far plane. \p far > \p + * near. + * @see setCustomProjection + * @see Engine::Config::stereoscopicEyeCount + */ + void setCustomEyeProjection(math::mat4 const* UTILS_NONNULL projection, size_t count, + math::mat4 const& projectionForCulling, double near, double far); + + /** Sets an additional matrix that scales the projection matrix. + * + * This is useful to adjust the aspect ratio of the camera independent from its projection. + * First, pass an aspect of 1.0 to setProjection. Then set the scaling with the desired aspect + * ratio: + * + * const double aspect = width / height; + * + * // with Fov::HORIZONTAL passed to setProjection: + * camera->setScaling(double4 {1.0, aspect}); + * + * // with Fov::VERTICAL passed to setProjection: + * camera->setScaling(double4 {1.0 / aspect, 1.0}); + * + * + * By default, this is an identity matrix. + * + * @param scaling diagonal of the 2x2 scaling matrix to be applied after the projection matrix. + * + * @see setProjection, setLensProjection, setCustomProjection + */ + void setScaling(math::double2 scaling) noexcept; + + /** + * Sets an additional matrix that shifts the projection matrix. + * By default, this is an identity matrix. + * + * @param shift x and y translation added to the projection matrix, specified in NDC + * coordinates, that is, if the translation must be specified in pixels, + * shift must be scaled by 1.0 / { viewport.width, viewport.height }. + * + * @see setProjection, setLensProjection, setCustomProjection + */ + void setShift(math::double2 shift) noexcept; + + /** Returns the scaling amount used to scale the projection matrix. + * + * @return the diagonal of the scaling matrix applied after the projection matrix. + * + * @see setScaling + */ + math::double4 getScaling() const noexcept; + + /** Returns the shift amount used to translate the projection matrix. + * + * @return the 2D translation x and y offsets applied after the projection matrix. + * + * @see setShift + */ + math::double2 getShift() const noexcept; + + /** Returns the projection matrix used for rendering. + * + * The projection matrix used for rendering always has its far plane set to infinity. This + * is why it may differ from the matrix set through setProjection() or setLensProjection(). + * + * @param eyeId the index of the eye to return the projection matrix for, must be + * < config.stereoscopicEyeCount + * @return The projection matrix used for rendering + * + * @see setProjection, setLensProjection, setCustomProjection, getCullingProjectionMatrix, + * setCustomEyeProjection + */ + math::mat4 getProjectionMatrix(uint8_t eyeId = 0) const; + + + /** Returns the projection matrix used for culling (far plane is finite). + * + * @return The projection matrix set by setProjection or setLensProjection. + * + * @see setProjection, setLensProjection, getProjectionMatrix + */ + math::mat4 getCullingProjectionMatrix() const noexcept; + + + //! Returns the frustum's near plane + double getNear() const noexcept; + + //! Returns the frustum's far plane used for culling + double getCullingFar() const noexcept; + + /** Sets the camera's model matrix. + * + * Helper method to set the camera's entity transform component. + * It has the same effect as calling: + * + * ~~~~~~~~~~~{.cpp} + * engine.getTransformManager().setTransform( + * engine.getTransformManager().getInstance(camera->getEntity()), model); + * ~~~~~~~~~~~ + * + * @param model The camera position and orientation provided as a rigid transform matrix. + * + * @note The Camera "looks" towards its -z axis + * + * @warning \p model must be a rigid transform + */ + void setModelMatrix(const math::mat4& model) noexcept; + void setModelMatrix(const math::mat4f& model) noexcept; //!< @overload + + /** Set the position of an eye relative to this Camera (head). + * + * By default, both eyes' model matrices are identity matrices. + * + * For example, to position Eye 0 3cm leftwards and Eye 1 3cm rightwards: + * ~~~~~~~~~~~{.cpp} + * const mat4 leftEye = mat4::translation(double3{-0.03, 0.0, 0.0}); + * const mat4 rightEye = mat4::translation(double3{ 0.03, 0.0, 0.0}); + * camera.setEyeModelMatrix(0, leftEye); + * camera.setEyeModelMatrix(1, rightEye); + * ~~~~~~~~~~~ + * + * This method is not intended to be called every frame. Instead, to update the position of the + * head, use Camera::setModelMatrix. + * + * @param eyeId the index of the eye to set, must be < config.stereoscopicEyeCount + * @param model the model matrix for an individual eye + */ + void setEyeModelMatrix(uint8_t eyeId, math::mat4 const& model); + + /** Sets the camera's model matrix + * + * @param eye The position of the camera in world space. + * @param center The point in world space the camera is looking at. + * @param up A unit vector denoting the camera's "up" direction. + */ + void lookAt(math::double3 const& eye, + math::double3 const& center, + math::double3 const& up = math::double3{0, 1, 0}) noexcept; + + /** Returns the camera's model matrix + * + * Helper method to return the camera's entity transform component. + * It has the same effect as calling: + * + * ~~~~~~~~~~~{.cpp} + * engine.getTransformManager().getWorldTransform( + * engine.getTransformManager().getInstance(camera->getEntity())); + * ~~~~~~~~~~~ + * + * @return The camera's pose in world space as a rigid transform. Parent transforms, if any, + * are taken into account. + */ + math::mat4 getModelMatrix() const noexcept; + + //! Returns the camera's view matrix (inverse of the model matrix) + math::mat4 getViewMatrix() const noexcept; + + //! Returns the camera's position in world space + math::double3 getPosition() const noexcept; + + //! Returns the camera's normalized left vector + math::float3 getLeftVector() const noexcept; + + //! Returns the camera's normalized up vector + math::float3 getUpVector() const noexcept; + + //! Returns the camera's forward vector + math::float3 getForwardVector() const noexcept; + + //! Returns the camera's field of view in degrees + float getFieldOfViewInDegrees(Fov direction) const noexcept; + + //! Returns the camera's culling Frustum in world space + class Frustum getFrustum() const noexcept; + + //! Returns the entity representing this camera + utils::Entity getEntity() const noexcept; + + /** Sets this camera's exposure (default is f/16, 1/125s, 100 ISO) + * + * The exposure ultimately controls the scene's brightness, just like with a real camera. + * The default values provide adequate exposure for a camera placed outdoors on a sunny day + * with the sun at the zenith. + * + * @param aperture Aperture in f-stops, clamped between 0.5 and 64. + * A lower \p aperture value *increases* the exposure, leading to + * a brighter scene. Realistic values are between 0.95 and 32. + * + * @param shutterSpeed Shutter speed in seconds, clamped between 1/25,000 and 60. + * A lower shutter speed increases the exposure. Realistic values are + * between 1/8000 and 30. + * + * @param sensitivity Sensitivity in ISO, clamped between 10 and 204,800. + * A higher \p sensitivity increases the exposure. Realistic values are + * between 50 and 25600. + * + * @note + * With the default parameters, the scene must contain at least one Light of intensity + * similar to the sun (e.g.: a 100,000 lux directional light). + * + * @see LightManager, Exposure + */ + void setExposure(float aperture, float shutterSpeed, float sensitivity) noexcept; + + /** Sets this camera's exposure directly. Calling this method will set the aperture + * to 1.0, the shutter speed to 1.2 and the sensitivity will be computed to match + * the requested exposure (for a desired exposure of 1.0, the sensitivity will be + * set to 100 ISO). + * + * This method is useful when trying to match the lighting of other engines or tools. + * Many engines/tools use unit-less light intensities, which can be matched by setting + * the exposure manually. This can be typically achieved by setting the exposure to + * 1.0. + */ + void setExposure(float exposure) noexcept { + setExposure(1.0f, 1.2f, 100.0f * (1.0f / exposure)); + } + + //! returns this camera's aperture in f-stops + float getAperture() const noexcept; + + //! returns this camera's shutter speed in seconds + float getShutterSpeed() const noexcept; + + //! returns this camera's sensitivity in ISO + float getSensitivity() const noexcept; + + /** Returns the focal length in meters [m] for a 35mm camera. + * Eye 0's projection matrix is used to compute the focal length. + */ + double getFocalLength() const noexcept; + + /** + * Sets the camera focus distance. This is used by the Depth-of-field PostProcessing effect. + * @param distance Distance from the camera to the plane of focus in world units. + * Must be positive and larger than the near clipping plane. + */ + void setFocusDistance(float distance) noexcept; + + //! Returns the focus distance in world units + float getFocusDistance() const noexcept; + + /** + * Returns the inverse of a projection matrix. + * + * \param p the projection matrix to inverse + * \returns the inverse of the projection matrix \p p + */ + static math::mat4 inverseProjection(const math::mat4& p) noexcept; + + /** + * Returns the inverse of a projection matrix. + * @see inverseProjection(const math::mat4&) + */ + static math::mat4f inverseProjection(const math::mat4f& p) noexcept; + + /** + * Helper to compute the effective focal length taking into account the focus distance + * + * @param focalLength focal length in any unit (e.g. [m] or [mm]) + * @param focusDistance focus distance in same unit as focalLength + * @return the effective focal length in same unit as focalLength + */ + static double computeEffectiveFocalLength(double focalLength, double focusDistance) noexcept; + + /** + * Helper to compute the effective field-of-view taking into account the focus distance + * + * @param fovInDegrees full field of view in degrees + * @param focusDistance focus distance in meters [m] + * @return effective full field of view in degrees + */ + static double computeEffectiveFov(double fovInDegrees, double focusDistance) noexcept; + +protected: + // prevent heap allocation + ~Camera() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_CAMERA_H diff --git a/package/android/libs/filament/include/filament/Color.h b/package/android/libs/filament/include/filament/Color.h new file mode 100644 index 00000000..30b77856 --- /dev/null +++ b/package/android/libs/filament/include/filament/Color.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_COLOR_H +#define TNT_FILAMENT_COLOR_H + +#include + +#include +#include + +#include +#include + +namespace filament { + +//! RGB color in linear space +using LinearColor = math::float3; + +//! RGB color in sRGB space +using sRGBColor = math::float3; + +//! RGBA color in linear space, with alpha +using LinearColorA = math::float4; + +//! RGBA color in sRGB space, with alpha +using sRGBColorA = math::float4; + +//! types of RGB colors +enum class RgbType : uint8_t { + sRGB, //!< the color is defined in Rec.709-sRGB-D65 (sRGB) space + LINEAR, //!< the color is defined in Rec.709-Linear-D65 ("linear sRGB") space +}; + +//! types of RGBA colors +enum class RgbaType : uint8_t { + /** + * the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values + * have not been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <1,0,0,0.5>) + */ + sRGB, + /** + * the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the + * RGB values have not been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <1,0,0,0.5>) + */ + LINEAR, + /** + * the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values + * have been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <0.5,0,0,0.5>) + */ + PREMULTIPLIED_sRGB, + /** + * the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the + * RGB values have been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <0.5,0,0,0.5>) + */ + PREMULTIPLIED_LINEAR +}; + +//! type of color conversion to use when converting to/from sRGB and linear spaces +enum ColorConversion { + ACCURATE, //!< accurate conversion using the sRGB standard + FAST //!< fast conversion using a simple gamma 2.2 curve +}; + +/** + * Utilities to manipulate and convert colors + */ +class UTILS_PUBLIC Color { +public: + //! converts an RGB color to linear space, the conversion depends on the specified type + static LinearColor toLinear(RgbType type, math::float3 color); + + //! converts an RGBA color to linear space, the conversion depends on the specified type + static LinearColorA toLinear(RgbaType type, math::float4 color); + + //! converts an RGB color in sRGB space to an RGB color in linear space + template + static LinearColor toLinear(sRGBColor const& color); + + /** + * Converts an RGB color in Rec.709-Linear-D65 ("linear sRGB") space to an + * RGB color in Rec.709-sRGB-D65 (sRGB) space. + */ + template + static sRGBColor toSRGB(LinearColor const& color); + + /** + * Converts an RGBA color in Rec.709-sRGB-D65 (sRGB) space to an RGBA color in + * Rec.709-Linear-D65 ("linear sRGB") space the alpha component is left unmodified. + */ + template + static LinearColorA toLinear(sRGBColorA const& color); + + /** + * Converts an RGBA color in Rec.709-Linear-D65 ("linear sRGB") space to + * an RGBA color in Rec.709-sRGB-D65 (sRGB) space the alpha component is + * left unmodified. + */ + template + static sRGBColorA toSRGB(LinearColorA const& color); + + /** + * Converts a correlated color temperature to a linear RGB color in sRGB + * space the temperature must be expressed in kelvin and must be in the + * range 1,000K to 15,000K. + */ + static LinearColor cct(float K); + + /** + * Converts a CIE standard illuminant series D to a linear RGB color in + * sRGB space the temperature must be expressed in kelvin and must be in + * the range 4,000K to 25,000K + */ + static LinearColor illuminantD(float K); + + /** + * Computes the Beer-Lambert absorption coefficients from the specified + * transmittance color and distance. The computed absorption will guarantee + * the white light will become the specified color at the specified distance. + * The output of this function can be used as the absorption parameter of + * materials that use refraction. + * + * @param color the desired linear RGB color in sRGB space + * @param distance the distance at which white light should become the specified color + * + * @return absorption coefficients for the Beer-Lambert law + */ + static math::float3 absorptionAtDistance(LinearColor const& color, float distance); + +private: + static math::float3 sRGBToLinear(math::float3 color) noexcept; + static math::float3 linearToSRGB(math::float3 color) noexcept; +}; + +// Use the default implementation from the header +template<> +inline LinearColor Color::toLinear(sRGBColor const& color) { + return pow(color, 2.2f); +} + +template<> +inline LinearColorA Color::toLinear(sRGBColorA const& color) { + return LinearColorA{pow(color.rgb, 2.2f), color.a}; +} + +template<> +inline LinearColor Color::toLinear(sRGBColor const& color) { + return sRGBToLinear(color); +} + +template<> +inline LinearColorA Color::toLinear(sRGBColorA const& color) { + return LinearColorA{sRGBToLinear(color.rgb), color.a}; +} + +// Use the default implementation from the header +template<> +inline sRGBColor Color::toSRGB(LinearColor const& color) { + return pow(color, 1.0f / 2.2f); +} + +template<> +inline sRGBColorA Color::toSRGB(LinearColorA const& color) { + return sRGBColorA{pow(color.rgb, 1.0f / 2.2f), color.a}; +} + +template<> +inline sRGBColor Color::toSRGB(LinearColor const& color) { + return linearToSRGB(color); +} + +template<> +inline sRGBColorA Color::toSRGB(LinearColorA const& color) { + return sRGBColorA{linearToSRGB(color.rgb), color.a}; +} + +inline LinearColor Color::toLinear(RgbType type, math::float3 color) { + return (type == RgbType::LINEAR) ? color : Color::toLinear(color); +} + +// converts an RGBA color to linear space +// the conversion depends on the specified type +inline LinearColorA Color::toLinear(RgbaType type, math::float4 color) { + switch (type) { + case RgbaType::sRGB: + return Color::toLinear(color) * math::float4{color.a, color.a, color.a, 1.0f}; + case RgbaType::LINEAR: + return color * math::float4{color.a, color.a, color.a, 1.0f}; + case RgbaType::PREMULTIPLIED_sRGB: + return Color::toLinear(color); + case RgbaType::PREMULTIPLIED_LINEAR: + return color; + } +} + +} // namespace filament + +#endif // TNT_FILAMENT_COLOR_H diff --git a/package/android/libs/filament/include/filament/ColorGrading.h b/package/android/libs/filament/include/filament/ColorGrading.h new file mode 100644 index 00000000..e5c8f3ca --- /dev/null +++ b/package/android/libs/filament/include/filament/ColorGrading.h @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_COLORGRADING_H +#define TNT_FILAMENT_COLORGRADING_H + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +class Engine; +class FColorGrading; + +namespace color { +class ColorSpace; +} + +/** + * ColorGrading is used to transform (either to modify or correct) the colors of the HDR buffer + * rendered by Filament. Color grading transforms are applied after lighting, and after any lens + * effects (bloom for instance), and include tone mapping. + * + * Creation, usage and destruction + * =============================== + * + * A ColorGrading object is created using the ColorGrading::Builder and destroyed by calling + * Engine::destroy(const ColorGrading*). A ColorGrading object is meant to be set on a View. + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::ColorGrading* colorGrading = filament::ColorGrading::Builder() + * .toneMapping(filament::ColorGrading::ToneMapping::ACES) + * .build(*engine); + * + * myView->setColorGrading(colorGrading); + * + * engine->destroy(colorGrading); + * ~~~~~~~~~~~ + * + * Performance + * =========== + * + * Creating a new ColorGrading object may be more expensive than other Filament objects as a + * 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on + * the CPU. + * + * Ordering + * ======== + * + * The various transforms held by ColorGrading are applied in the following order: + * - Exposure + * - Night adaptation + * - White balance + * - Channel mixer + * - Shadows/mid-tones/highlights + * - Slope/offset/power (CDL) + * - Contrast + * - Vibrance + * - Saturation + * - Curves + * - Tone mapping + * - Luminance scaling + * - Gamut mapping + * + * Defaults + * ======== + * + * Here are the default color grading options: + * - Exposure: 0.0 + * - Night adaptation: 0.0 + * - White balance: temperature 0, and tint 0 + * - Channel mixer: red {1,0,0}, green {0,1,0}, blue {0,0,1} + * - Shadows/mid-tones/highlights: shadows {1,1,1,0}, mid-tones {1,1,1,0}, highlights {1,1,1,0}, + * ranges {0,0.333,0.550,1} + * - Slope/offset/power: slope 1.0, offset 0.0, and power 1.0 + * - Contrast: 1.0 + * - Vibrance: 1.0 + * - Saturation: 1.0 + * - Curves: gamma {1,1,1}, midPoint {1,1,1}, and scale {1,1,1} + * - Tone mapping: ACESLegacyToneMapper + * - Luminance scaling: false + * - Gamut mapping: false + * - Output color space: Rec709-sRGB-D65 + * + * @see View + */ +class UTILS_PUBLIC ColorGrading : public FilamentAPI { + struct BuilderDetails; +public: + + enum class QualityLevel : uint8_t { + LOW, + MEDIUM, + HIGH, + ULTRA + }; + + enum class LutFormat : uint8_t { + INTEGER, //!< 10 bits per component + FLOAT, //!< 16 bits per component (10 bits mantissa precision) + }; + + + /** + * List of available tone-mapping operators. + * + * @deprecated Use Builder::toneMapper(ToneMapper*) instead + */ + enum class UTILS_DEPRECATED ToneMapping : uint8_t { + LINEAR = 0, //!< Linear tone mapping (i.e. no tone mapping) + ACES_LEGACY = 1, //!< ACES tone mapping, with a brightness modifier to match Filament's legacy tone mapper + ACES = 2, //!< ACES tone mapping + FILMIC = 3, //!< Filmic tone mapping, modelled after ACES but applied in sRGB space + DISPLAY_RANGE = 4, //!< Tone mapping used to validate/debug scene exposure + }; + + //! Use Builder to construct a ColorGrading object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Sets the quality level of the color grading. When color grading is implemented using + * a 3D LUT, the quality level may impact the resolution and bit depth of the backing + * 3D texture. For instance, a low quality level will use a 16x16x16 10 bit LUT, a medium + * quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit + * LUT, and a ultra quality will use a 64x64x64 16 bit LUT. + * This overrides the values set by format() and dimensions(). + * + * The default quality is medium. + * + * @param qualityLevel The desired quality of the color grading process + * + * @return This Builder, for chaining calls + */ + Builder& quality(QualityLevel qualityLevel) noexcept; + + /** + * When color grading is implemented using a 3D LUT, this sets the texture format of + * of the LUT. This overrides the value set by quality(). + * + * The default is INTEGER + * + * @param format The desired format of the 3D LUT. + * + * @return This Builder, for chaining calls + */ + Builder& format(LutFormat format) noexcept; + + /** + * When color grading is implemented using a 3D LUT, this sets the dimension of the LUT. + * This overrides the value set by quality(). + * + * The default is 32 + * + * @param dim The desired dimension of the LUT. Between 16 and 64. + * + * @return This Builder, for chaining calls + */ + Builder& dimensions(uint8_t dim) noexcept; + + /** + * Selects the tone mapping operator to apply to the HDR color buffer as the last + * operation of the color grading post-processing step. + * + * The default tone mapping operator is ACESLegacyToneMapper. + * + * The specified tone mapper must have a lifecycle that exceeds the lifetime of + * this builder. Since the build(Engine&) method is synchronous, it is safe to + * delete the tone mapper object after that finishes executing. + * + * @param toneMapper The tone mapping operator to apply to the HDR color buffer + * + * @return This Builder, for chaining calls + */ + Builder& toneMapper(ToneMapper const* UTILS_NULLABLE toneMapper) noexcept; + + /** + * Selects the tone mapping operator to apply to the HDR color buffer as the last + * operation of the color grading post-processing step. + * + * The default tone mapping operator is ACES_LEGACY. + * + * @param toneMapping The tone mapping operator to apply to the HDR color buffer + * + * @return This Builder, for chaining calls + * + * @deprecated Use toneMapper(ToneMapper*) instead + */ + UTILS_DEPRECATED + Builder& toneMapping(ToneMapping toneMapping) noexcept; + + /** + * Enables or disables the luminance scaling component (LICH) from the exposure value + * invariant luminance system (EVILS). When this setting is enabled, pixels with high + * chromatic values will roll-off to white to offer a more natural rendering. This step + * also helps avoid undesirable hue skews caused by out of gamut colors clipped + * to the destination color gamut. + * + * When luminance scaling is enabled, tone mapping is performed on the luminance of each + * pixel instead of per-channel. + * + * @param luminanceScaling Enables or disables luminance scaling post-tone mapping + * + * @return This Builder, for chaining calls + */ + Builder& luminanceScaling(bool luminanceScaling) noexcept; + + /** + * Enables or disables gamut mapping to the destination color space's gamut. When gamut + * mapping is turned off, out-of-gamut colors are clipped to the destination's gamut, + * which may produce hue skews (blue skewing to purple, green to yellow, etc.). When + * gamut mapping is enabled, out-of-gamut colors are brought back in gamut by trying to + * preserve the perceived chroma and lightness of the original values. + * + * @param gamutMapping Enables or disables gamut mapping + * + * @return This Builder, for chaining calls + */ + Builder& gamutMapping(bool gamutMapping) noexcept; + + /** + * Adjusts the exposure of this image. The exposure is specified in stops: + * each stop brightens (positive values) or darkens (negative values) the image by + * a factor of 2. This means that an exposure of 3 will brighten the image 8 times + * more than an exposure of 0 (2^3 = 8 and 2^0 = 1). Contrary to the camera's exposure, + * this setting is applied after all post-processing (bloom, etc.) are applied. + * + * @param exposure Value in EV stops. Can be negative, 0, or positive. + * + * @return This Builder, for chaining calls + */ + Builder& exposure(float exposure) noexcept; + + /** + * Controls the amount of night adaptation to replicate a more natural representation of + * low-light conditions as perceived by the human vision system. In low-light conditions, + * peak luminance sensitivity of the eye shifts toward the blue end of the color spectrum: + * darker tones appear brighter, reducing contrast, and colors are blue shifted (the darker + * the more intense the effect). + * + * @param adaptation Amount of adaptation, between 0 (no adaptation) and 1 (full adaptation). + * + * @return This Builder, for chaining calls + */ + Builder& nightAdaptation(float adaptation) noexcept; + + /** + * Adjusts the while balance of the image. This can be used to remove color casts + * and correct the appearance of the white point in the scene, or to alter the + * overall chromaticity of the image for artistic reasons (to make the image appear + * cooler or warmer for instance). + * + * The while balance adjustment is defined with two values: + * - Temperature, to modify the color temperature. This value will modify the colors + * on a blue/yellow axis. Lower values apply a cool color temperature, and higher + * values apply a warm color temperature. The lowest value, -1.0f, is equivalent to + * a temperature of 50,000K. The highest value, 1.0f, is equivalent to a temperature + * of 2,000K. + * - Tint, to modify the colors on a green/magenta axis. The lowest value, -1.0f, will + * apply a strong green cast, and the highest value, 1.0f, will apply a strong magenta + * cast. + * + * Both values are expected to be in the range [-1.0..+1.0]. Values outside of that + * range will be clipped to that range. + * + * @param temperature Modification on the blue/yellow axis, as a value between -1.0 and +1.0. + * @param tint Modification on the green/magenta axis, as a value between -1.0 and +1.0. + * + * @return This Builder, for chaining calls + */ + Builder& whiteBalance(float temperature, float tint) noexcept; + + /** + * The channel mixer adjustment modifies each output color channel using the specified + * mix of the source color channels. + * + * By default each output color channel is set to use 100% of the corresponding source + * channel and 0% of the other channels. For instance, the output red channel is set to + * {1.0, 0.0, 1.0} or 100% red, 0% green and 0% blue. + * + * Each output channel can add or subtract data from the source channel by using values + * in the range [-2.0..+2.0]. Values outside of that range will be clipped to that range. + * + * Using the channel mixer adjustment you can for instance create a monochrome output + * by setting all 3 output channels to the same mix. For instance: {0.4, 0.4, 0.2} for + * all 3 output channels(40% red, 40% green and 20% blue). + * + * More complex mixes can be used to create more complex effects. For instance, here is + * a mix that creates a sepia tone effect: + * - outRed = {0.255, 0.858, 0.087} + * - outGreen = {0.213, 0.715, 0.072} + * - outBlue = {0.170, 0.572, 0.058} + * + * @param outRed The mix of source RGB for the output red channel, between -2.0 and +2.0 + * @param outGreen The mix of source RGB for the output green channel, between -2.0 and +2.0 + * @param outBlue The mix of source RGB for the output blue channel, between -2.0 and +2.0 + * + * @return This Builder, for chaining calls + */ + Builder& channelMixer( + math::float3 outRed, math::float3 outGreen, math::float3 outBlue) noexcept; + + /** + * Adjusts the colors separately in 3 distinct tonal ranges or zones: shadows, mid-tones, + * and highlights. + * + * The tonal zones are by the ranges parameter: the x and y components define the beginning + * and end of the transition from shadows to mid-tones, and the z and w components define + * the beginning and end of the transition from mid-tones to highlights. + * + * A smooth transition is applied between the zones which means for instance that the + * correction color of the shadows range will partially apply to the mid-tones, and the + * other way around. This ensure smooth visual transitions in the final image. + * + * Each correction color is defined as a linear RGB color and a weight. The weight is a + * value (which may be positive or negative) that is added to the linear RGB color before + * mixing. This can be used to darken or brighten the selected tonal range. + * + * Shadows/mid-tones/highlights adjustment are performed linear space. + * + * @param shadows Linear RGB color (.rgb) and weight (.w) to apply to the shadows + * @param midtones Linear RGB color (.rgb) and weight (.w) to apply to the mid-tones + * @param highlights Linear RGB color (.rgb) and weight (.w) to apply to the highlights + * @param ranges Range of the shadows (x and y), and range of the highlights (z and w) + * + * @return This Builder, for chaining calls + */ + Builder& shadowsMidtonesHighlights( + math::float4 shadows, math::float4 midtones, math::float4 highlights, + math::float4 ranges) noexcept; + + /** + * Applies a slope, offset, and power, as defined by the ASC CDL (American Society of + * Cinematographers Color Decision List) to the image. The CDL can be used to adjust the + * colors of different tonal ranges in the image. + * + * The ASC CDL is similar to the lift/gamma/gain controls found in many color grading tools. + * Lift is equivalent to a combination of offset and slope, gain is equivalent to slope, + * and gamma is equivalent to power. + * + * The slope and power values must be strictly positive. Values less than or equal to 0 will + * be clamped to a small positive value, offset can be any positive or negative value. + * + * Version 1.2 of the ASC CDL adds saturation control, which is here provided as a separate + * API. See the saturation() method for more information. + * + * Slope/offset/power adjustments are performed in log space. + * + * @param slope Multiplier of the input color, must be a strictly positive number + * @param offset Added to the input color, can be a negative or positive number, including 0 + * @param power Power exponent of the input color, must be a strictly positive number + * + * @return This Builder, for chaining calls + */ + Builder& slopeOffsetPower(math::float3 slope, math::float3 offset, math::float3 power) noexcept; + + /** + * Adjusts the contrast of the image. Lower values decrease the contrast of the image + * (the tonal range is narrowed), and higher values increase the contrast of the image + * (the tonal range is widened). A value of 1.0 has no effect. + * + * The contrast is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Contrast adjustment is performed in log space. + * + * @param contrast Contrast expansion, between 0.0 and 2.0. 1.0 leaves contrast unaffected + * + * @return This Builder, for chaining calls + */ + Builder& contrast(float contrast) noexcept; + + /** + * Adjusts the saturation of the image based on the input color's saturation level. + * Colors with a high level of saturation are less affected than colors with low saturation + * levels. + * + * Lower vibrance values decrease intensity of the colors present in the image, and + * higher values increase the intensity of the colors in the image. A value of 1.0 has + * no effect. + * + * The vibrance is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Vibrance adjustment is performed in linear space. + * + * @param vibrance Vibrance, between 0.0 and 2.0. 1.0 leaves vibrance unaffected + * + * @return This Builder, for chaining calls + */ + Builder& vibrance(float vibrance) noexcept; + + /** + * Adjusts the saturation of the image. Lower values decrease intensity of the colors + * present in the image, and higher values increase the intensity of the colors in the + * image. A value of 1.0 has no effect. + * + * The saturation is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Saturation adjustment is performed in linear space. + * + * @param saturation Saturation, between 0.0 and 2.0. 1.0 leaves saturation unaffected + * + * @return This Builder, for chaining calls + */ + Builder& saturation(float saturation) noexcept; + + /** + * Applies a curve to each RGB channel of the image. Each curve is defined by 3 values: + * a gamma value applied to the shadows only, a mid-point indicating where shadows stop + * and highlights start, and a scale factor for the highlights. + * + * The gamma and mid-point must be strictly positive values. If they are not, they will be + * clamped to a small positive value. The scale can be any negative of positive value. + * + * Curves are applied in linear space. + * + * @param shadowGamma Power value to apply to the shadows, must be strictly positive + * @param midPoint Mid-point defining where shadows stop and highlights start, must be strictly positive + * @param highlightScale Scale factor for the highlights, can be any negative or positive value + * + * @return This Builder, for chaining calls + */ + Builder& curves(math::float3 shadowGamma, math::float3 midPoint, math::float3 highlightScale) noexcept; + + /** + * Sets the output color space for this ColorGrading object. After all color grading steps + * have been applied, the final color will be converted in the desired color space. + * + * NOTE: Currently the output color space must be one of Rec709-sRGB-D65 or + * Rec709-Linear-D65. Only the transfer function is taken into account. + * + * @param colorSpace The output color space. + * + * @return This Builder, for chaining calls + */ + Builder& outputColorSpace(const color::ColorSpace& colorSpace) noexcept; + + /** + * Creates the ColorGrading object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this ColorGrading with. + * + * @return pointer to the newly created object. + */ + ColorGrading* UTILS_NONNULL build(Engine& engine); + + private: + friend class FColorGrading; + }; + +protected: + // prevent heap allocation + ~ColorGrading() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_COLORGRADING_H diff --git a/package/android/libs/filament/include/filament/ColorSpace.h b/package/android/libs/filament/include/filament/ColorSpace.h new file mode 100644 index 00000000..d8890955 --- /dev/null +++ b/package/android/libs/filament/include/filament/ColorSpace.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_COLOR_SPACE_H +#define TNT_FILAMENT_COLOR_SPACE_H + +#include + +namespace filament::color { + +using namespace math; + +/** + * Holds the chromaticities of a color space's primaries as xy coordinates + * in xyY (Y is assumed to be 1). + */ +struct Primaries { + float2 r; + float2 g; + float2 b; + + bool operator==(const Primaries& rhs) const noexcept { + return r == rhs.r && b == rhs.b && g == rhs.g; + } +}; + +//! Reference white for a color space, defined as the xy coordinates in the xyY space. +using WhitePoint = float2; + +/** + *

Defines the parameters for the ICC parametric curve type 4, as + * defined in ICC.1:2004-10, section 10.15.

+ * + *

The EOTF is of the form:

+ * + * \(\begin{equation} + * Y = \begin{cases}c X + f & X \lt d \\\ + * \left( a X + b \right) ^{g} + e & X \ge d \end{cases} + * \end{equation}\) + * + *

The corresponding OETF is simply the inverse function.

+ * + *

The parameters defined by this class form a valid transfer + * function only if all the following conditions are met:

+ *
    + *
  • No parameter is a NaN
  • + *
  • \(d\) is in the range \([0..1]\)
  • + *
  • The function is not constant
  • + *
  • The function is positive and increasing
  • + *
+ */ +struct TransferFunction { + /** + *

Defines the parameters for the ICC parametric curve type 3, as + * defined in ICC.1:2004-10, section 10.15.

+ * + *

The EOTF is of the form:

+ * + * \(\begin{equation} + * Y = \begin{cases}c X & X \lt d \\\ + * \left( a X + b \right) ^{g} & X \ge d \end{cases} + * \end{equation}\) + * + *

This constructor is equivalent to setting \(e\) and \(f\) to 0.

+ * + * @param a The value of \(a\) in the equation of the EOTF described above + * @param b The value of \(b\) in the equation of the EOTF described above + * @param c The value of \(c\) in the equation of the EOTF described above + * @param d The value of \(d\) in the equation of the EOTF described above + * @param g The value of \(g\) in the equation of the EOTF described above + */ + constexpr TransferFunction( + double a, + double b, + double c, + double d, + double e, + double f, + double g + ) : a(a), + b(b), + c(c), + d(d), + e(e), + f(f), + g(g) { + } + + constexpr TransferFunction( + double a, + double b, + double c, + double d, + double g + ) : TransferFunction(a, b, c, d, 0.0, 0.0, g) { + } + + bool operator==(const TransferFunction& rhs) const noexcept { + return + a == rhs.a && + b == rhs.b && + c == rhs.c && + d == rhs.d && + e == rhs.e && + f == rhs.f && + g == rhs.g; + } + + double a; + double b; + double c; + double d; + double e; + double f; + double g; +}; + +/** + *

A color space in Filament is always an RGB color space. A specific RGB color space + * is defined by the following properties:

+ *
    + *
  • Three chromaticities of the red, green and blue primaries, which + * define the gamut of the color space.
  • + *
  • A white point chromaticity that defines the stimulus to which + * color space values are normalized (also just called "white").
  • + *
  • An opto-electronic transfer function, also called opto-electronic + * conversion function or often, and approximately, gamma function.
  • + *
  • An electro-optical transfer function, also called electo-optical + * conversion function or often, and approximately, gamma function.
  • + *
+ * + *

Primaries and white point chromaticities

+ *

In this implementation, the chromaticity of the primaries and the white + * point of an RGB color space is defined in the CIE xyY color space. This + * color space separates the chromaticity of a color, the x and y components, + * and its luminance, the Y component. Since the primaries and the white + * point have full brightness, the Y component is assumed to be 1 and only + * the x and y components are needed to encode them.

+ * + *

Transfer functions

+ *

A transfer function is a color component conversion function, defined as + * a single variable, monotonic mathematical function. It is applied to each + * individual component of a color. They are used to perform the mapping + * between linear tristimulus values and non-linear electronic signal value.

+ *

The opto-electronic transfer function (OETF or OECF) encodes + * tristimulus values in a scene to a non-linear electronic signal value.

+ */ +class ColorSpace { +public: + constexpr ColorSpace( + const Primaries primaries, + const TransferFunction transferFunction, + const WhitePoint whitePoint + ) : mPrimaries(primaries), + mTransferFunction(transferFunction), + mWhitePoint(whitePoint) { + } + + bool operator==(const ColorSpace& rhs) const noexcept { + return mPrimaries == rhs.mPrimaries && + mTransferFunction == rhs.mTransferFunction && + mWhitePoint == rhs.mWhitePoint; + } + + constexpr const Primaries& getPrimaries() const { return mPrimaries; } + constexpr const TransferFunction& getTransferFunction() const { return mTransferFunction; } + constexpr const WhitePoint& getWhitePoint() const { return mWhitePoint; } + +private: + Primaries mPrimaries; + TransferFunction mTransferFunction; + WhitePoint mWhitePoint; +}; + +/** + * Intermediate class used when building a color space using the "-" syntax: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * // Declares a "linear sRGB" color space. + * ColorSpace myColorSpace = Rec709-Linear-D65; + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class PartialColorSpace { +public: + constexpr ColorSpace operator-(const WhitePoint& whitePoint) const { + return { mPrimaries, mTransferFunction, whitePoint }; + } + +private: + constexpr PartialColorSpace( + const Primaries primaries, + const TransferFunction transferFunction + ) : mPrimaries(primaries), + mTransferFunction(transferFunction) { + } + + Primaries mPrimaries; + TransferFunction mTransferFunction; + + friend class Gamut; +}; + +/** + * Defines the chromaticities of the primaries for a color space. The chromaticities + * are expressed as three pairs of xy coordinates (in xyY) for the red, green, and blue + * chromaticities. + */ +class Gamut { +public: + constexpr explicit Gamut(const Primaries primaries) : mPrimaries(primaries) { + } + + constexpr Gamut(float2 r, float2 g, float2 b) : Gamut(Primaries{ r, g, b }) { + } + + constexpr PartialColorSpace operator-(const TransferFunction& transferFunction) const { + return { mPrimaries, transferFunction }; + } + + constexpr const Primaries& getPrimaries() const { return mPrimaries; } + +private: + Primaries mPrimaries; +}; + +//! Rec.709 color gamut, used in the sRGB and DisplayP3 color spaces. +constexpr Gamut Rec709 = {{ 0.640f, 0.330f }, + { 0.300f, 0.600f }, + { 0.150f, 0.060f }}; + +//! Linear transfer function. +constexpr TransferFunction Linear = { 1.0, 0.0, 0.0, 0.0, 1.0 }; + +//! sRGB transfer function. +constexpr TransferFunction sRGB = { 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045, 2.4 }; + +//! Standard CIE 1931 2° illuminant D65. This illuminant has a color temperature of 6504K. +constexpr WhitePoint D65 = { 0.31271f, 0.32902f }; + +} // namespace filament::color + +#endif // TNT_FILAMENT_COLOR_SPACE_H diff --git a/package/android/libs/filament/include/filament/DebugRegistry.h b/package/android/libs/filament/include/filament/DebugRegistry.h new file mode 100644 index 00000000..d5e1d8e9 --- /dev/null +++ b/package/android/libs/filament/include/filament/DebugRegistry.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_DEBUGREGISTRY_H +#define TNT_FILAMENT_DEBUGREGISTRY_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * A registry of runtime properties used exclusively for debugging + * + * Filament exposes a few properties that can be queried and set, which control certain debugging + * features of the engine. These properties can be set at runtime at anytime. + * + */ +class UTILS_PUBLIC DebugRegistry : public FilamentAPI { +public: + + /** + * Queries whether a property exists + * @param name The name of the property to query + * @return true if the property exists, false otherwise + */ + bool hasProperty(const char* UTILS_NONNULL name) const noexcept; + + /** + * Queries the address of a property's data from its name + * @param name Name of the property we want the data address of + * @return Address of the data of the \p name property + * @{ + */ + void* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name); + + void const* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) const noexcept; + + template + inline T* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) { + return static_cast(getPropertyAddress(name)); + } + + template + inline T const* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) const noexcept { + return static_cast(getPropertyAddress(name)); + } + + template + inline bool getPropertyAddress(const char* UTILS_NONNULL name, + T* UTILS_NULLABLE* UTILS_NONNULL p) { + *p = getPropertyAddress(name); + return *p != nullptr; + } + + template + inline bool getPropertyAddress(const char* UTILS_NONNULL name, + T* const UTILS_NULLABLE* UTILS_NONNULL p) const noexcept { + *p = getPropertyAddress(name); + return *p != nullptr; + } + /** @}*/ + + /** + * Set the value of a property + * @param name Name of the property to set the value of + * @param v Value to set + * @return true if the operation was successful, false otherwise. + * @{ + */ + bool setProperty(const char* UTILS_NONNULL name, bool v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, int v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, float v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float2 v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float3 v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float4 v) noexcept; + /** @}*/ + + /** + * Get the value of a property + * @param name Name of the property to get the value of + * @param v A pointer to a variable which will hold the result + * @return true if the call was successful and \p v was updated + * @{ + */ + bool getProperty(const char* UTILS_NONNULL name, bool* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, int* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, float* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float2* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float3* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float4* UTILS_NONNULL v) const noexcept; + /** @}*/ + + struct DataSource { + void const* UTILS_NULLABLE data; + size_t count; + }; + + DataSource getDataSource(const char* UTILS_NONNULL name) const noexcept; + + struct FrameHistory { + using duration_ms = float; + duration_ms target{}; + duration_ms targetWithHeadroom{}; + duration_ms frameTime{}; + duration_ms frameTimeDenoised{}; + float scale = 1.0f; + float pid_e = 0.0f; + float pid_i = 0.0f; + float pid_d = 0.0f; + }; + +protected: + // prevent heap allocation + ~DebugRegistry() = default; +}; + + +} // namespace filament + +#endif /* TNT_FILAMENT_DEBUGREGISTRY_H */ diff --git a/package/android/libs/filament/include/filament/Engine.h b/package/android/libs/filament/include/filament/Engine.h new file mode 100644 index 00000000..493573cc --- /dev/null +++ b/package/android/libs/filament/include/filament/Engine.h @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_ENGINE_H +#define TNT_FILAMENT_ENGINE_H + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace utils { +class Entity; +class EntityManager; +class JobSystem; +} // namespace utils + +namespace filament { + +class BufferObject; +class Camera; +class ColorGrading; +class DebugRegistry; +class Fence; +class IndexBuffer; +class SkinningBuffer; +class IndirectLight; +class Material; +class MaterialInstance; +class MorphTargetBuffer; +class Renderer; +class RenderTarget; +class Scene; +class Skybox; +class Stream; +class SwapChain; +class Texture; +class VertexBuffer; +class View; +class InstanceBuffer; + +class LightManager; +class RenderableManager; +class TransformManager; + +#ifndef FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB +# define FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB 3 +#endif + +#ifndef FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB +# define FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB 2 +#endif + +#ifndef FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB +# define FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB 1 +#endif + +#ifndef FILAMENT_COMMAND_BUFFER_SIZE_IN_MB +# define FILAMENT_COMMAND_BUFFER_SIZE_IN_MB (FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB * 3) +#endif + +/** + * Engine is filament's main entry-point. + * + * An Engine instance main function is to keep track of all resources created by the user and + * manage the rendering thread as well as the hardware renderer. + * + * To use filament, an Engine instance must be created first: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Engine essentially represents (or is associated to) a hardware context + * (e.g. an OpenGL ES context). + * + * Rendering typically happens in an operating system's window (which can be full screen), such + * window is managed by a filament.Renderer. + * + * A typical filament render loop looks like this: + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * Renderer* renderer = engine->createRenderer(); + * Scene* scene = engine->createScene(); + * View* view = engine->createView(); + * + * view->setScene(scene); + * + * do { + * // typically we wait for VSYNC and user input events + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } while (!quit); + * + * engine->destroy(view); + * engine->destroy(scene); + * engine->destroy(renderer); + * engine->destroy(swapChain); + * Engine::destroy(&engine); // clears engine* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Resource Tracking + * ================= + * + * Each Engine instance keeps track of all objects created by the user, such as vertex and index + * buffers, lights, cameras, etc... + * The user is expected to free those resources, however, leaked resources are freed when the + * engine instance is destroyed and a warning is emitted in the console. + * + * Thread safety + * ============= + * + * An Engine instance is not thread-safe. The implementation makes no attempt to synchronize + * calls to an Engine instance methods. + * If multi-threading is needed, synchronization must be external. + * + * Multi-threading + * =============== + * + * When created, the Engine instance starts a render thread as well as multiple worker threads, + * these threads have an elevated priority appropriate for rendering, based on the platform's + * best practices. The number of worker threads depends on the platform and is automatically + * chosen for best performance. + * + * On platforms with asymmetric cores (e.g. ARM's Big.Little), Engine makes some educated guesses + * as to which cores to use for the render thread and worker threads. For example, it'll try to + * keep an OpenGL ES thread on a Big core. + * + * Swap Chains + * =========== + * + * A swap chain represents an Operating System's *native* renderable surface. Typically it's a window + * or a view. Because a SwapChain is initialized from a native object, it is given to filament + * as a `void*`, which must be of the proper type for each platform filament is running on. + * + * @see SwapChain + * + * + * @see Renderer + */ +class UTILS_PUBLIC Engine { + struct BuilderDetails; +public: + using Platform = backend::Platform; + using Backend = backend::Backend; + using DriverConfig = backend::Platform::DriverConfig; + using FeatureLevel = backend::FeatureLevel; + using StereoscopicType = backend::StereoscopicType; + + /** + * Config is used to define the memory footprint used by the engine, such as the + * command buffer size. Config can be used to customize engine requirements based + * on the applications needs. + * + * .perRenderPassArenaSizeMB (default: 3 MiB) + * +--------------------------+ + * | | + * | .perFrameCommandsSizeMB | + * | (default 2 MiB) | + * | | + * +--------------------------+ + * | (froxel, etc...) | + * +--------------------------+ + * + * + * .commandBufferSizeMB (default 3MiB) + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * : : + * : : + * + */ + struct Config { + /** + * Size in MiB of the low-level command buffer arena. + * + * Each new command buffer is allocated from here. If this buffer is too small the program + * might terminate or rendering errors might occur. + * + * This is typically set to minCommandBufferSizeMB * 3, so that up to 3 frames can be + * batched-up at once. + * + * This value affects the application's memory usage. + */ + uint32_t commandBufferSizeMB = FILAMENT_COMMAND_BUFFER_SIZE_IN_MB; + + + /** + * Size in MiB of the per-frame data arena. + * + * This is the main arena used for allocations when preparing a frame. + * e.g.: Froxel data and high-level commands are allocated from this arena. + * + * If this size is too small, the program will abort on debug builds and have undefined + * behavior otherwise. + * + * This value affects the application's memory usage. + */ + uint32_t perRenderPassArenaSizeMB = FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB; + + + /** + * Size in MiB of the backend's handle arena. + * + * Backends will fallback to slower heap-based allocations when running out of space and + * log this condition. + * + * If 0, then the default value for the given platform is used + * + * This value affects the application's memory usage. + */ + uint32_t driverHandleArenaSizeMB = 0; + + + /** + * Minimum size in MiB of a low-level command buffer. + * + * This is how much space is guaranteed to be available for low-level commands when a new + * buffer is allocated. If this is too small, the engine might have to stall to wait for + * more space to become available, this situation is logged. + * + * This value does not affect the application's memory usage. + */ + uint32_t minCommandBufferSizeMB = FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB; + + + /** + * Size in MiB of the per-frame high level command buffer. + * + * This buffer is related to the number of draw calls achievable within a frame, if it is + * too small, the program will abort on debug builds and have undefined behavior otherwise. + * + * It is allocated from the 'per-render-pass arena' above. Make sure that at least 1 MiB is + * left in the per-render-pass arena when deciding the size of this buffer. + * + * This value does not affect the application's memory usage. + */ + uint32_t perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB; + + /** + * Number of threads to use in Engine's JobSystem. + * + * Engine uses a utils::JobSystem to carry out paralleization of Engine workloads. This + * value sets the number of threads allocated for JobSystem. Configuring this value can be + * helpful in CPU-constrained environments where too many threads can cause contention of + * CPU and reduce performance. + * + * The default value is 0, which implies that the Engine will use a heuristic to determine + * the number of threads to use. + */ + uint32_t jobSystemThreadCount = 0; + + /* + * Number of most-recently destroyed textures to track for use-after-free. + * + * This will cause the backend to throw an exception when a texture is freed but still bound + * to a SamplerGroup and used in a draw call. 0 disables completely. + * + * Currently only respected by the Metal backend. + */ + size_t textureUseAfterFreePoolSize = 0; + + /* + * The type of technique for stereoscopic rendering. + * + * This setting determines the algorithm used when stereoscopic rendering is enabled. This + * decision applies to the entire Engine for the lifetime of the Engine. E.g., multiple + * Views created from the Engine must use the same stereoscopic type. + * + * Each view can enable stereoscopic rendering via the StereoscopicOptions::enable flag. + * + * @see View::setStereoscopicOptions + */ + StereoscopicType stereoscopicType = StereoscopicType::INSTANCED; + + /* + * The number of eyes to render when stereoscopic rendering is enabled. Supported values are + * between 1 and Engine::getMaxStereoscopicEyes() (inclusive). + * + * @see View::setStereoscopicOptions + * @see Engine::getMaxStereoscopicEyes + */ + uint8_t stereoscopicEyeCount = 2; + + /* + * Size in MiB of the frame graph texture cache. This should be adjusted based on the + * size of used render targets (typically the screen). + */ + uint32_t resourceAllocatorCacheSizeMB = 64; + + /* + * This value determines for how many frames are texture entries kept in the cache. + * The default value of 30 corresponds to about half a second at 60 fps. + */ + uint32_t resourceAllocatorCacheMaxAge = 30; + }; + + +#if UTILS_HAS_THREADING + using CreateCallback = void(void* UTILS_NULLABLE user, void* UTILS_NONNULL token); +#endif + + /** + * Engine::Builder is used to create a new filament Engine. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + friend class FEngine; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * @param backend Which driver backend to use + * @return A reference to this Builder for chaining calls. + */ + Builder& backend(Backend backend) noexcept; + + /** + * @param platform A pointer to an object that implements Platform. If this is + * provided, then this object is used to create the hardware context + * and expose platform features to it. + * + * If not provided (or nullptr is used), an appropriate Platform + * is created automatically. + * + * All methods of this interface are called from filament's + * render thread, which is different from the main thread. + * + * The lifetime of \p platform must exceed the lifetime of + * the Engine object. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& platform(Platform* UTILS_NULLABLE platform) noexcept; + + /** + * @param config A pointer to optional parameters to specify memory size + * configuration options. If nullptr, then defaults used. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& config(const Config* UTILS_NULLABLE config) noexcept; + + /** + * @param sharedContext A platform-dependant context used as a shared context + * when creating filament's internal context. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& sharedContext(void* UTILS_NULLABLE sharedContext) noexcept; + + /** + * @param featureLevel The feature level at which initialize Filament. + * @return A reference to this Builder for chaining calls. + */ + Builder& featureLevel(FeatureLevel featureLevel) noexcept; + +#if UTILS_HAS_THREADING + /** + * Creates the filament Engine asynchronously. + * + * @param callback Callback called once the engine is initialized and it is safe to + * call Engine::getEngine(). + */ + void build(utils::Invocable&& callback) const; +#endif + + /** + * Creates an instance of Engine. + * + * @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be + * created. + * nullptr if the GPU driver couldn't be initialized, for instance if it doesn't + * support the right version of OpenGL or OpenGL ES. + * + * @exception utils::PostConditionPanic can be thrown if there isn't enough memory to + * allocate the command buffer. If exceptions are disabled, this condition if + * fatal and this function will abort. + */ + Engine* UTILS_NULLABLE build() const; + }; + + /** + * Backward compatibility helper to create an Engine. + * @see Builder + */ + static inline Engine* UTILS_NULLABLE create(Backend backend = Backend::DEFAULT, + Platform* UTILS_NULLABLE platform = nullptr, + void* UTILS_NULLABLE sharedContext = nullptr, + const Config* UTILS_NULLABLE config = nullptr) { + return Engine::Builder() + .backend(backend) + .platform(platform) + .sharedContext(sharedContext) + .config(config) + .build(); + } + + +#if UTILS_HAS_THREADING + /** + * Backward compatibility helper to create an Engine asynchronously. + * @see Builder + */ + static inline void createAsync(CreateCallback callback, + void* UTILS_NULLABLE user, + Backend backend = Backend::DEFAULT, + Platform* UTILS_NULLABLE platform = nullptr, + void* UTILS_NULLABLE sharedContext = nullptr, + const Config* UTILS_NULLABLE config = nullptr) { + Engine::Builder() + .backend(backend) + .platform(platform) + .sharedContext(sharedContext) + .config(config) + .build([callback, user](void* UTILS_NONNULL token) { + callback(user, token); + }); + } + + /** + * Retrieve an Engine* from createAsync(). This must be called from the same thread than + * Engine::createAsync() was called from. + * + * @param token An opaque token given in the createAsync() callback function. + * + * @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be created. + * + * @exception utils::PostConditionPanic can be thrown if there isn't enough memory to + * allocate the command buffer. If exceptions are disabled, this condition if fatal and + * this function will abort. + */ + static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token); +#endif + + + /** + * Destroy the Engine instance and all associated resources. + * + * Engine.destroy() should be called last and after all other resources have been destroyed, + * it ensures all filament resources are freed. + * + * Destroy performs the following tasks: + * 1. Destroy all internal software and hardware resources. + * 2. Free all user allocated resources that are not already destroyed and logs a warning. + * This indicates a "leak" in the user's code. + * 3. Terminate the rendering engine's thread. + * + * @param engine A pointer to the filament.Engine* to be destroyed. + * \p engine is cleared upon return. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * Engine::destroy(&engine); // clears engine* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \remark + * This method is thread-safe. + */ + static void destroy(Engine* UTILS_NULLABLE* UTILS_NULLABLE engine); + + /** + * Destroy the Engine instance and all associated resources. + * + * Engine.destroy() should be called last and after all other resources have been destroyed, + * it ensures all filament resources are freed. + * + * Destroy performs the following tasks: + * 1. Destroy all internal software and hardware resources. + * 2. Free all user allocated resources that are not already destroyed and logs a warning. + * This indicates a "leak" in the user's code. + * 3. Terminate the rendering engine's thread. + * + * @param engine A pointer to the filament.Engine to be destroyed. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * Engine::destroy(engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \remark + * This method is thread-safe. + */ + static void destroy(Engine* UTILS_NULLABLE engine); + + /** + * Query the feature level supported by the selected backend. + * + * A specific feature level needs to be set before the corresponding features can be used. + * + * @return FeatureLevel supported the selected backend. + * @see setActiveFeatureLevel + */ + FeatureLevel getSupportedFeatureLevel() const noexcept; + + /** + * Activate all features of a given feature level. If an explicit feature level is not specified + * at Engine initialization time via Builder::featureLevel, the default feature level is + * FeatureLevel::FEATURE_LEVEL_0 on devices not compatible with GLES 3.0; otherwise, the default + * is FeatureLevel::FEATURE_LEVEL_1. The selected feature level must not be higher than the + * value returned by getActiveFeatureLevel() and it's not possible lower the active feature + * level. Additionally, it is not possible to modify the feature level at all if the Engine was + * initialized at FeatureLevel::FEATURE_LEVEL_0. + * + * @param featureLevel the feature level to activate. If featureLevel is lower than + * getActiveFeatureLevel(), the current (higher) feature level is kept. If + * featureLevel is higher than getSupportedFeatureLevel(), or if the engine + * was initialized at feature level 0, an exception is thrown, or the + * program is terminated if exceptions are disabled. + * + * @return the active feature level. + * + * @see Builder::featureLevel + * @see getSupportedFeatureLevel + * @see getActiveFeatureLevel + */ + FeatureLevel setActiveFeatureLevel(FeatureLevel featureLevel); + + /** + * Returns the currently active feature level. + * @return currently active feature level + * @see getSupportedFeatureLevel + * @see setActiveFeatureLevel + */ + FeatureLevel getActiveFeatureLevel() const noexcept; + + /** + * Queries the maximum number of GPU instances that Filament creates when automatic instancing + * is enabled. This value is also the limit for the number of transforms that can be stored in + * an InstanceBuffer. This value may depend on the device and platform, but will remain constant + * during the lifetime of this Engine. + * + * This value does not apply when using the instances(size_t) method on + * RenderableManager::Builder. + * + * @return the number of max automatic instances + * @see setAutomaticInstancingEnabled + * @see RenderableManager::Builder::instances(size_t) + * @see RenderableManager::Builder::instances(size_t, InstanceBuffer*) + */ + size_t getMaxAutomaticInstances() const noexcept; + + /** + * Queries the device and platform for support of the given stereoscopic type. + * + * @return true if the given stereo rendering is supported, false otherwise + * @see View::setStereoscopicOptions + */ + bool isStereoSupported(StereoscopicType stereoscopicType) const noexcept; + + /** + * Retrieves the configuration settings of this Engine. + * + * This method returns the configuration object that was supplied to the Engine's + * Builder::config method during the creation of this Engine. If the Builder::config method was + * not explicitly called (or called with nullptr), this method returns the default configuration + * settings. + * + * @return a Config object with this Engine's configuration + * @see Builder::config + */ + const Config& getConfig() const noexcept; + + /** + * Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of + * eyes rendered is set at Engine creation time with the Engine::Config::stereoscopicEyeCount + * setting. + * + * @return the max number of stereoscopic eyes supported + * @see Engine::Config::stereoscopicEyeCount + */ + static size_t getMaxStereoscopicEyes() noexcept; + + /** + * @return EntityManager used by filament + */ + utils::EntityManager& getEntityManager() noexcept; + + /** + * @return RenderableManager reference + */ + RenderableManager& getRenderableManager() noexcept; + + /** + * @return LightManager reference + */ + LightManager& getLightManager() noexcept; + + /** + * @return TransformManager reference + */ + TransformManager& getTransformManager() noexcept; + + /** + * Helper to enable accurate translations. + * If you need this Engine to handle a very large world space, one way to achieve this + * automatically is to enable accurate translations in the TransformManager. This helper + * provides a convenient way of doing that. + * This is typically called once just after creating the Engine. + */ + void enableAccurateTranslations() noexcept; + + /** + * Enables or disables automatic instancing of render primitives. Instancing of render + * primitives can greatly reduce CPU overhead but requires the instanced primitives to be + * identical (i.e. use the same geometry) and use the same MaterialInstance. If it is known + * that the scene doesn't contain any identical primitives, automatic instancing can have some + * overhead and it is then best to disable it. + * + * Disabled by default. + * + * @param enable true to enable, false to disable automatic instancing. + * + * @see RenderableManager + * @see MaterialInstance + */ + void setAutomaticInstancingEnabled(bool enable) noexcept; + + /** + * @return true if automatic instancing is enabled, false otherwise. + * @see setAutomaticInstancingEnabled + */ + bool isAutomaticInstancingEnabled() const noexcept; + + /** + * Creates a SwapChain from the given Operating System's native window handle. + * + * @param nativeWindow An opaque native window handle. e.g.: on Android this is an + * `ANativeWindow*`. + * @param flags One or more configuration flags as defined in `SwapChain`. + * + * @return A pointer to the newly created SwapChain. + * + * @see Renderer.beginFrame() + */ + SwapChain* UTILS_NONNULL createSwapChain(void* UTILS_NULLABLE nativeWindow, uint64_t flags = 0) noexcept; + + + /** + * Creates a headless SwapChain. + * + * @param width Width of the drawing buffer in pixels. + * @param height Height of the drawing buffer in pixels. + * @param flags One or more configuration flags as defined in `SwapChain`. + * + * @return A pointer to the newly created SwapChain. + * + * @see Renderer.beginFrame() + */ + SwapChain* UTILS_NONNULL createSwapChain(uint32_t width, uint32_t height, uint64_t flags = 0) noexcept; + + /** + * Creates a renderer associated to this engine. + * + * A Renderer is intended to map to a *window* on screen. + * + * @return A pointer to the newly created Renderer. + */ + Renderer* UTILS_NONNULL createRenderer() noexcept; + + /** + * Creates a View. + * + * @return A pointer to the newly created View. + */ + View* UTILS_NONNULL createView() noexcept; + + /** + * Creates a Scene. + * + * @return A pointer to the newly created Scene. + */ + Scene* UTILS_NONNULL createScene() noexcept; + + /** + * Creates a Camera component. + * + * @param entity Entity to add the camera component to. + * @return A pointer to the newly created Camera. + */ + Camera* UTILS_NONNULL createCamera(utils::Entity entity) noexcept; + + /** + * Returns the Camera component of the given entity. + * + * @param entity An entity. + * @return A pointer to the Camera component for this entity or nullptr if the entity didn't + * have a Camera component. The pointer is valid until destroyCameraComponent() + * is called or the entity itself is destroyed. + */ + Camera* UTILS_NULLABLE getCameraComponent(utils::Entity entity) noexcept; + + /** + * Destroys the Camera component associated with the given entity. + * + * @param entity An entity. + */ + void destroyCameraComponent(utils::Entity entity) noexcept; + + /** + * Creates a Fence. + * + * @return A pointer to the newly created Fence. + */ + Fence* UTILS_NONNULL createFence() noexcept; + + bool destroy(const BufferObject* UTILS_NULLABLE p); //!< Destroys a BufferObject object. + bool destroy(const VertexBuffer* UTILS_NULLABLE p); //!< Destroys an VertexBuffer object. + bool destroy(const Fence* UTILS_NULLABLE p); //!< Destroys a Fence object. + bool destroy(const IndexBuffer* UTILS_NULLABLE p); //!< Destroys an IndexBuffer object. + bool destroy(const SkinningBuffer* UTILS_NULLABLE p); //!< Destroys a SkinningBuffer object. + bool destroy(const MorphTargetBuffer* UTILS_NULLABLE p); //!< Destroys a MorphTargetBuffer object. + bool destroy(const IndirectLight* UTILS_NULLABLE p); //!< Destroys an IndirectLight object. + + /** + * Destroys a Material object + * @param p the material object to destroy + * @attention All MaterialInstance of the specified material must be destroyed before + * destroying it. + * @exception utils::PreConditionPanic is thrown if some MaterialInstances remain. + * no-op if exceptions are disabled and some MaterialInstances remain. + */ + bool destroy(const Material* UTILS_NULLABLE p); + bool destroy(const MaterialInstance* UTILS_NULLABLE p); //!< Destroys a MaterialInstance object. + bool destroy(const Renderer* UTILS_NULLABLE p); //!< Destroys a Renderer object. + bool destroy(const Scene* UTILS_NULLABLE p); //!< Destroys a Scene object. + bool destroy(const Skybox* UTILS_NULLABLE p); //!< Destroys a SkyBox object. + bool destroy(const ColorGrading* UTILS_NULLABLE p); //!< Destroys a ColorGrading object. + bool destroy(const SwapChain* UTILS_NULLABLE p); //!< Destroys a SwapChain object. + bool destroy(const Stream* UTILS_NULLABLE p); //!< Destroys a Stream object. + bool destroy(const Texture* UTILS_NULLABLE p); //!< Destroys a Texture object. + bool destroy(const RenderTarget* UTILS_NULLABLE p); //!< Destroys a RenderTarget object. + bool destroy(const View* UTILS_NULLABLE p); //!< Destroys a View object. + bool destroy(const InstanceBuffer* UTILS_NULLABLE p); //!< Destroys an InstanceBuffer object. + void destroy(utils::Entity e); //!< Destroys all filament-known components from this entity + + bool isValid(const BufferObject* UTILS_NULLABLE p); //!< Tells whether a BufferObject object is valid + bool isValid(const VertexBuffer* UTILS_NULLABLE p); //!< Tells whether an VertexBuffer object is valid + bool isValid(const Fence* UTILS_NULLABLE p); //!< Tells whether a Fence object is valid + bool isValid(const IndexBuffer* UTILS_NULLABLE p); //!< Tells whether an IndexBuffer object is valid + bool isValid(const SkinningBuffer* UTILS_NULLABLE p); //!< Tells whether a SkinningBuffer object is valid + bool isValid(const MorphTargetBuffer* UTILS_NULLABLE p); //!< Tells whether a MorphTargetBuffer object is valid + bool isValid(const IndirectLight* UTILS_NULLABLE p); //!< Tells whether an IndirectLight object is valid + bool isValid(const Material* UTILS_NULLABLE p); //!< Tells whether an IndirectLight object is valid + bool isValid(const Renderer* UTILS_NULLABLE p); //!< Tells whether a Renderer object is valid + bool isValid(const Scene* UTILS_NULLABLE p); //!< Tells whether a Scene object is valid + bool isValid(const Skybox* UTILS_NULLABLE p); //!< Tells whether a SkyBox object is valid + bool isValid(const ColorGrading* UTILS_NULLABLE p); //!< Tells whether a ColorGrading object is valid + bool isValid(const SwapChain* UTILS_NULLABLE p); //!< Tells whether a SwapChain object is valid + bool isValid(const Stream* UTILS_NULLABLE p); //!< Tells whether a Stream object is valid + bool isValid(const Texture* UTILS_NULLABLE p); //!< Tells whether a Texture object is valid + bool isValid(const RenderTarget* UTILS_NULLABLE p); //!< Tells whether a RenderTarget object is valid + bool isValid(const View* UTILS_NULLABLE p); //!< Tells whether a View object is valid + bool isValid(const InstanceBuffer* UTILS_NULLABLE p); //!< Tells whether an InstanceBuffer object is valid + + /** + * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until + * all commands to this point are executed. Note that does guarantee that the + * hardware is actually finished. + * + *

This is typically used right after destroying the SwapChain, + * in cases where a guarantee about the SwapChain destruction is needed in a + * timely fashion, such as when responding to Android's + * android.view.SurfaceHolder.Callback.surfaceDestroyed

+ */ + void flushAndWait(); + + /** + * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait + * for commands to be either executed or the hardware finished. + * + *

This is typically used after creating a lot of objects to start draining the command + * queue which has a limited size.

+ */ + void flush(); + + /** + * Drains the user callback message queue and immediately execute all pending callbacks. + * + *

Typically this should be called once per frame right after the application's vsync tick, + * and typically just before computing parameters (e.g. object positions) for the next frame. + * This is useful because otherwise callbacks will be executed by filament at a later time, + * which may increase latency in certain applications.

+ */ + void pumpMessageQueues(); + + /** + * Returns the default Material. + * + * The default material is 80% white and uses the Material.Shading.LIT shading. + * + * @return A pointer to the default Material instance (a singleton). + */ + Material const* UTILS_NONNULL getDefaultMaterial() const noexcept; + + /** + * Returns the resolved backend. + */ + Backend getBackend() const noexcept; + + /** + * Returns the Platform object that belongs to this Engine. + * + * When Engine::create is called with no platform argument, Filament creates an appropriate + * Platform subclass automatically. The specific subclass created depends on the backend and + * OS. For example, when the OpenGL backend is used, the Platform object will be a descendant of + * OpenGLPlatform. + * + * dynamic_cast should be used to cast the returned Platform object into a specific subclass. + * Note that RTTI must be available to use dynamic_cast. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Platform* platform = engine->getPlatform(); + * // static_cast also works, but more dangerous. + * SpecificPlatform* specificPlatform = dynamic_cast(platform); + * specificPlatform->platformSpecificMethod(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * When a custom Platform is passed to Engine::create, Filament will use it instead, and this + * method will return it. + * + * @return A pointer to the Platform object that was provided to Engine::create, or the + * Filament-created one. + */ + Platform* UTILS_NULLABLE getPlatform() const noexcept; + + /** + * Allocate a small amount of memory directly in the command stream. The allocated memory is + * guaranteed to be preserved until the current command buffer is executed + * + * @param size size to allocate in bytes. This should be small (e.g. < 1 KB) + * @param alignment alignment requested + * @return a pointer to the allocated buffer or nullptr if no memory was available. + * + * @note there is no need to destroy this buffer, it will be freed automatically when + * the current command buffer is executed. + */ + void* UTILS_NULLABLE streamAlloc(size_t size, size_t alignment = alignof(double)) noexcept; + + /** + * Invokes one iteration of the render loop, used only on single-threaded platforms. + * + * This should be called every time the windowing system needs to paint (e.g. at 60 Hz). + */ + void execute(); + + /** + * Retrieves the job system that the Engine has ownership over. + * + * @return JobSystem used by filament + */ + utils::JobSystem& getJobSystem() noexcept; + +#if defined(__EMSCRIPTEN__) + /** + * WebGL only: Tells the driver to reset any internal state tracking if necessary. + * + * This is only useful when integrating an external renderer into Filament on platforms + * like WebGL, where share contexts do not exist. Filament keeps track of the GL + * state it has set (like which texture is bound), and does not re-set that state if + * it does not think it needs to. However, if an external renderer has set different + * state in the mean time, Filament will use that new state unknowingly. + * + * If you are in this situation, call this function - ideally only once per frame, + * immediately after calling Engine::execute(). + */ + void resetBackendState() noexcept; +#endif + + DebugRegistry& getDebugRegistry() noexcept; + +protected: + //! \privatesection + Engine() noexcept = default; + ~Engine() = default; + +public: + //! \privatesection + Engine(Engine const&) = delete; + Engine(Engine&&) = delete; + Engine& operator=(Engine const&) = delete; + Engine& operator=(Engine&&) = delete; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_ENGINE_H diff --git a/package/android/libs/filament/include/filament/Exposure.h b/package/android/libs/filament/include/filament/Exposure.h new file mode 100644 index 00000000..a1e545f7 --- /dev/null +++ b/package/android/libs/filament/include/filament/Exposure.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_EXPOSURE_H +#define TNT_FILAMENT_EXPOSURE_H + +#include + +namespace filament { + +class Camera; + +/** + * A series of utilities to compute exposure, exposure value at ISO 100 (EV100), + * luminance and illuminance using a physically-based camera model. + */ +namespace Exposure { + +/** + * Returns the exposure value (EV at ISO 100) of the specified camera. + */ +UTILS_PUBLIC +float ev100(const Camera& camera) noexcept; + +/** + * Returns the exposure value (EV at ISO 100) of the specified exposure parameters. + */ +UTILS_PUBLIC +float ev100(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Returns the exposure value (EV at ISO 100) for the given average luminance (in @f$ \frac{cd}{m^2} @f$). + */ +UTILS_PUBLIC +float ev100FromLuminance(float luminance) noexcept; + +/** +* Returns the exposure value (EV at ISO 100) for the given illuminance (in lux). +*/ +UTILS_PUBLIC +float ev100FromIlluminance(float illuminance) noexcept; + +/** + * Returns the photometric exposure for the specified camera. + */ +UTILS_PUBLIC +float exposure(const Camera& camera) noexcept; + +/** + * Returns the photometric exposure for the specified exposure parameters. + * This function is equivalent to calling `exposure(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float exposure(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Returns the photometric exposure for the given EV100. + */ +UTILS_PUBLIC +float exposure(float ev100) noexcept; + +/** + * Returns the incident luminance in @f$ \frac{cd}{m^2} @f$ for the specified camera acting as a spot meter. + */ +UTILS_PUBLIC +float luminance(const Camera& camera) noexcept; + +/** + * Returns the incident luminance in @f$ \frac{cd}{m^2} @f$ for the specified exposure parameters of + * a camera acting as a spot meter. + * This function is equivalent to calling `luminance(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float luminance(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Converts the specified EV100 to luminance in @f$ \frac{cd}{m^2} @f$. + * EV100 is not a measure of luminance, but an EV100 can be used to denote a + * luminance for which a camera would use said EV100 to obtain the nominally + * correct exposure + */ +UTILS_PUBLIC +float luminance(float ev100) noexcept; + +/** + * Returns the illuminance in lux for the specified camera acting as an incident light meter. + */ +UTILS_PUBLIC +float illuminance(const Camera& camera) noexcept; + +/** + * Returns the illuminance in lux for the specified exposure parameters of + * a camera acting as an incident light meter. + * This function is equivalent to calling `illuminance(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float illuminance(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Converts the specified EV100 to illuminance in lux. + * EV100 is not a measure of illuminance, but an EV100 can be used to denote an + * illuminance for which a camera would use said EV100 to obtain the nominally + * correct exposure. + */ +UTILS_PUBLIC +float illuminance(float ev100) noexcept; + +} // namespace exposure +} // namespace filament + +#endif // TNT_FILAMENT_EXPOSURE_H diff --git a/package/android/libs/filament/include/filament/Fence.h b/package/android/libs/filament/include/filament/Fence.h new file mode 100644 index 00000000..673d12cd --- /dev/null +++ b/package/android/libs/filament/include/filament/Fence.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_FENCE_H +#define TNT_FILAMENT_FENCE_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * Fence is used to synchronize the application main thread with filament's rendering thread. + */ +class UTILS_PUBLIC Fence : public FilamentAPI { +public: + //! Special \p timeout value to disable wait()'s timeout. + static constexpr uint64_t FENCE_WAIT_FOR_EVER = backend::FENCE_WAIT_FOR_EVER; + + //! Error codes for Fence::wait() + using FenceStatus = backend::FenceStatus; + + /** Mode controls the behavior of the command stream when calling wait() + * + * @attention + * It would be unwise to call `wait(..., Mode::DONT_FLUSH)` from the same thread + * the Fence was created, as it would most certainly create a dead-lock. + */ + enum class Mode : uint8_t { + FLUSH, //!< The command stream is flushed + DONT_FLUSH //!< The command stream is not flushed + }; + + /** + * Client-side wait on the Fence. + * + * Blocks the current thread until the Fence signals. + * + * @param mode Whether the command stream is flushed before waiting or not. + * @param timeout Wait time out. Using a \p timeout of 0 is a way to query the state of the fence. + * A \p timeout value of FENCE_WAIT_FOR_EVER is used to disable the timeout. + * @return FenceStatus::CONDITION_SATISFIED on success, + * FenceStatus::TIMEOUT_EXPIRED if the time out expired or + * FenceStatus::ERROR in other cases. + * @see #Mode + */ + FenceStatus wait(Mode mode = Mode::FLUSH, uint64_t timeout = FENCE_WAIT_FOR_EVER); + + /** + * Client-side wait on a Fence and destroy the Fence. + * + * @param fence Fence object to wait on. + * + * @param mode Whether the command stream is flushed before waiting or not. + * + * @return FenceStatus::CONDITION_SATISFIED on success, + * FenceStatus::ERROR otherwise. + */ + static FenceStatus waitAndDestroy(Fence* UTILS_NONNULL fence, Mode mode = Mode::FLUSH); + +protected: + // prevent heap allocation + ~Fence() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_FENCE_H diff --git a/package/android/libs/filament/include/filament/FilamentAPI.h b/package/android/libs/filament/include/filament/FilamentAPI.h new file mode 100644 index 00000000..19d6ba24 --- /dev/null +++ b/package/android/libs/filament/include/filament/FilamentAPI.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_FILAMENTAPI_H +#define TNT_FILAMENT_FILAMENTAPI_H + +#include +#include + +#include + +namespace filament { + +/** + * \privatesection + * FilamentAPI is used to define an API in filament. + * It ensures the class defining the API can't be created, destroyed + * or copied by the caller. + */ +class UTILS_PUBLIC FilamentAPI { +protected: + // disallow creation on the stack + FilamentAPI() noexcept = default; + ~FilamentAPI() = default; + +public: + // disallow copy and assignment + FilamentAPI(FilamentAPI const&) = delete; + FilamentAPI(FilamentAPI&&) = delete; + FilamentAPI& operator=(FilamentAPI const&) = delete; + FilamentAPI& operator=(FilamentAPI&&) = delete; + + // allow placement-new allocation, don't use "noexcept", to avoid compiler null check + static void *operator new (size_t, void* p) { return p; } + + // prevent heap allocation + static void *operator new (size_t) = delete; + static void *operator new[] (size_t) = delete; +}; + +template +using BuilderBase = utils::PrivateImplementation; + +} // namespace filament + +#endif // TNT_FILAMENT_FILAMENTAPI_H diff --git a/package/android/libs/filament/include/filament/Frustum.h b/package/android/libs/filament/include/filament/Frustum.h new file mode 100644 index 00000000..ceec55eb --- /dev/null +++ b/package/android/libs/filament/include/filament/Frustum.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_FRUSTUM_H +#define TNT_FILAMENT_FRUSTUM_H + +#include + +#include +#include +#include + +#include // Because we define NEAR and FAR in the Plane enum. + +#include + +namespace filament { + +class Box; +class Culler; + +/** + * A frustum defined by six planes + */ +class UTILS_PUBLIC Frustum { +public: + enum class Plane : uint8_t { + LEFT, + RIGHT, + BOTTOM, + TOP, + FAR, + NEAR + }; + + Frustum() = default; + Frustum(const Frustum& rhs) = default; + Frustum(Frustum&& rhs) noexcept = default; + Frustum& operator=(const Frustum& rhs) = default; + Frustum& operator=(Frustum&& rhs) noexcept = default; + + /** + * Creates a frustum from a projection matrix in GL convention + * (usually the projection * view matrix) + * @param pv a 4x4 projection matrix in GL convention + */ + explicit Frustum(const math::mat4f& pv); + + /** + * Sets the frustum from the given projection matrix + * @param pv a 4x4 projection matrix + */ + void setProjection(const math::mat4f& pv); + + /** + * Returns the plane equation parameters with normalized normals + * @param plane Identifier of the plane to retrieve the equation of + * @return A plane equation encoded a float4 R such as R.x*x + R.y*y + R.z*z + R.w = 0 + */ + math::float4 getNormalizedPlane(Plane plane) const noexcept; + + /** + * Returns a copy of all six frustum planes in left, right, bottom, top, far, near order + * @param planes six plane equations encoded as in getNormalizedPlane() in + * left, right, bottom, top, far, near order + */ + void getNormalizedPlanes(math::float4 planes[UTILS_NONNULL 6]) const noexcept; + + /** + * Returns all six frustum planes in left, right, bottom, top, far, near order + * @return six plane equations encoded as in getNormalizedPlane() in + * left, right, bottom, top, far, near order + */ + math::float4 const* UTILS_NONNULL getNormalizedPlanes() const noexcept { return mPlanes; } + + /** + * Returns whether a box intersects the frustum (i.e. is visible) + * @param box The box to test against the frustum + * @return true if the box may intersects the frustum, false otherwise. In some situations + * a box that doesn't intersect the frustum might be reported as though it does. However, + * a box that does intersect the frustum is always reported correctly (true). + */ + bool intersects(const Box& box) const noexcept; + + /** + * Returns whether a sphere intersects the frustum (i.e. is visible) + * @param sphere A sphere encoded as a center + radius. + * @return true if the sphere may intersects the frustum, false otherwise. In some situations + * a sphere that doesn't intersect the frustum might be reported as though it does. However, + * a sphere that does intersect the frustum is always reported correctly (true). + */ + bool intersects(const math::float4& sphere) const noexcept; + + /** + * Returns whether the frustum contains a given point. + * @param p the point to test + * @return the maximum signed distance to the frustum. Negative if p is inside. + */ + float contains(math::float3 p) const noexcept; + +private: + friend class Culler; + math::float4 mPlanes[6]; +}; + +} // namespace filament + +#if !defined(NDEBUG) +namespace utils::io { +class ostream; +} // namespace utils::io +utils::io::ostream& operator<<(utils::io::ostream& out, filament::Frustum const& frustum); +#endif + +#endif // TNT_FILAMENT_FRUSTUM_H diff --git a/package/android/libs/filament/include/filament/IndexBuffer.h b/package/android/libs/filament/include/filament/IndexBuffer.h new file mode 100644 index 00000000..35b8a10e --- /dev/null +++ b/package/android/libs/filament/include/filament/IndexBuffer.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_INDEXBUFFER_H +#define TNT_FILAMENT_INDEXBUFFER_H + +#include + +#include + +#include + +#include + +#include +#include + +namespace filament { + +class FIndexBuffer; + +class Engine; + +/** + * A buffer containing vertex indices into a VertexBuffer. Indices can be 16 or 32 bit. + * The buffer itself is a GPU resource, therefore mutating the data can be relatively slow. + * Typically these buffers are constant. + * + * It is possible, and even encouraged, to use a single index buffer for several Renderables. + * + * @see VertexBuffer, RenderableManager + */ +class UTILS_PUBLIC IndexBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + using BufferDescriptor = backend::BufferDescriptor; + + /** + * Type of the index buffer + */ + enum class IndexType : uint8_t { + USHORT = uint8_t(backend::ElementType::USHORT), //!< 16-bit indices + UINT = uint8_t(backend::ElementType::UINT), //!< 32-bit indices + }; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the index buffer in elements. + * @param indexCount Number of indices the IndexBuffer can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& indexCount(uint32_t indexCount) noexcept; + + /** + * Type of the index buffer, 16-bit or 32-bit. + * @param indexType Type of indices stored in the IndexBuffer. + * @return A reference to this Builder for chaining calls. + */ + Builder& bufferType(IndexType indexType) noexcept; + + /** + * Creates the IndexBuffer object and returns a pointer to it. After creation, the index + * buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer. + * + * @param engine Reference to the filament::Engine to associate this IndexBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see IndexBuffer::setBuffer + */ + IndexBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FIndexBuffer; + }; + + /** + * Asynchronously copy-initializes a region of this IndexBuffer from the data provided. + * + * @param engine Reference to the filament::Engine to associate this IndexBuffer with. + * @param buffer A BufferDescriptor representing the data used to initialize the IndexBuffer. + * BufferDescriptor points to raw, untyped data that will be interpreted as + * either 16-bit or 32-bits indices based on the Type of this IndexBuffer. + * @param byteOffset Offset in *bytes* into the IndexBuffer + */ + void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0); + + /** + * Returns the size of this IndexBuffer in elements. + * @return The number of indices the IndexBuffer holds. + */ + size_t getIndexCount() const noexcept; + +protected: + // prevent heap allocation + ~IndexBuffer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_INDEXBUFFER_H diff --git a/package/android/libs/filament/include/filament/IndirectLight.h b/package/android/libs/filament/include/filament/IndirectLight.h new file mode 100644 index 00000000..c230dac8 --- /dev/null +++ b/package/android/libs/filament/include/filament/IndirectLight.h @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_INDIRECTLIGHT_H +#define TNT_FILAMENT_INDIRECTLIGHT_H + +#include + +#include + +#include + +#include + +namespace filament { + +class Engine; +class Texture; + +class FIndirectLight; + +/** + * IndirectLight is used to simulate environment lighting, a form of global illumination. + * + * Environment lighting has a two components: + * 1. irradiance + * 2. reflections (specular component) + * + * Environments are usually captured as high-resolution HDR equirectangular images and processed + * by the **cmgen** tool to generate the data needed by IndirectLight. + * + * @note + * Currently IndirectLight is intended to be used for "distant probes", that is, to represent + * global illumination from a distant (i.e. at infinity) environment, such as the sky or distant + * mountains. Only a single IndirectLight can be used in a Scene. This limitation will be lifted + * in the future. + * + * Creation and destruction + * ======================== + * + * An IndirectLight object is created using the IndirectLight::Builder and destroyed by calling + * Engine::destroy(const IndirectLight*). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::IndirectLight* environment = filament::IndirectLight::Builder() + * .reflections(cubemap) + * .build(*engine); + * + * engine->destroy(environment); + * ~~~~~~~~~~~ + * + * + * Irradiance + * ========== + * + * The irradiance represents the light that comes from the environment and shines an + * object's surface. + * + * The irradiance is calculated automatically from the Reflections (see below), and generally + * doesn't need to be provided explicitly. However, it can be provided separately from the + * Reflections as + * [spherical harmonics](https://en.wikipedia.org/wiki/Spherical_harmonics) (SH) of 1, 2 or + * 3 bands, respectively 1, 4 or 9 coefficients. + * + * @note + * Use the **cmgen** tool to generate the `SH` for a given environment. + * + * Reflections + * =========== + * + * The reflections on object surfaces (specular component) is calculated from a specially + * filtered cubemap pyramid generated by the **cmgen** tool. + * + * + * @see Scene, Light, Texture, Skybox + */ +class UTILS_PUBLIC IndirectLight : public FilamentAPI { + struct BuilderDetails; + +public: + + //! Use Builder to construct an IndirectLight object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Set the reflections cubemap mipmap chain. + * + * @param cubemap A mip-mapped cubemap generated by **cmgen**. Each cubemap level + * encodes a the irradiance for a roughness level. + * + * @return This Builder, for chaining calls. + * + */ + Builder& reflections(Texture const* UTILS_NULLABLE cubemap) noexcept; + + /** + * Sets the irradiance as Spherical Harmonics. + * + * The irradiance must be pre-convolved by \f$ \langle n \cdot l \rangle \f$ and + * pre-multiplied by the Lambertian diffuse BRDF \f$ \frac{1}{\pi} \f$ and + * specified as Spherical Harmonics coefficients. + * + * Additionally, these Spherical Harmonics coefficients must be pre-scaled by the + * reconstruction factors \f$ A_{l}^{m} \f$ below. + * + * The final coefficients can be generated using the `cmgen` tool. + * + * The index in the \p sh array is given by: + * + * `index(l, m) = l * (l + 1) + m` + * + * \f$ sh[index(l,m)] = L_{l}^{m} \frac{1}{\pi} A_{l}^{m} \hat{C_{l}} \f$ + * + * index | l | m | \f$ A_{l}^{m} \f$ | \f$ \hat{C_{l}} \f$ | \f$ \frac{1}{\pi} A_{l}^{m}\hat{C_{l}} \f$ | + * :-----:|:---:|:---:|:------------------:|:---------------------:|:--------------------------------------------: + * 0 | 0 | 0 | 0.282095 | 3.1415926 | 0.282095 + * 1 | 1 | -1 | -0.488602 | 2.0943951 | -0.325735 + * 2 | ^ | 0 | 0.488602 | ^ | 0.325735 + * 3 | ^ | 1 | -0.488602 | ^ | -0.325735 + * 4 | 2 | -2 | 1.092548 | 0.785398 | 0.273137 + * 5 | ^ | -1 | -1.092548 | ^ | -0.273137 + * 6 | ^ | 0 | 0.315392 | ^ | 0.078848 + * 7 | ^ | 1 | -1.092548 | ^ | -0.273137 + * 8 | ^ | 2 | 0.546274 | ^ | 0.136569 + * + * + * Only 1, 2 or 3 bands are allowed. + * + * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. + * @param sh Array containing the spherical harmonics coefficients. + * The size of the array must be \f$ bands^{2} \f$. + * (i.e. 1, 4 or 9 coefficients respectively). + * + * @return This Builder, for chaining calls. + * + * @note + * Because the coefficients are pre-scaled, `sh[0]` is the environment's + * average irradiance. + */ + Builder& irradiance(uint8_t bands, math::float3 const* UTILS_NONNULL sh) noexcept; + + /** + * Sets the irradiance from the radiance expressed as Spherical Harmonics. + * + * The radiance must be specified as Spherical Harmonics coefficients \f$ L_{l}^{m} \f$ + * + * The index in the \p sh array is given by: + * + * `index(l, m) = l * (l + 1) + m` + * + * \f$ sh[index(l,m)] = L_{l}^{m} \f$ + * + * index | l | m + * :-----:|:---:|:---: + * 0 | 0 | 0 + * 1 | 1 | -1 + * 2 | ^ | 0 + * 3 | ^ | 1 + * 4 | 2 | -2 + * 5 | ^ | -1 + * 6 | ^ | 0 + * 7 | ^ | 1 + * 8 | ^ | 2 + * + * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. + * @param sh Array containing the spherical harmonics coefficients. + * The size of the array must be \f$ bands^{2} \f$. + * (i.e. 1, 4 or 9 coefficients respectively). + * + * @return This Builder, for chaining calls. + */ + Builder& radiance(uint8_t bands, math::float3 const* UTILS_NONNULL sh) noexcept; + + /** + * Sets the irradiance as a cubemap. + * + * The irradiance can alternatively be specified as a cubemap instead of Spherical + * Harmonics coefficients. It may or may not be more efficient, depending on your + * hardware (essentially, it's trading ALU for bandwidth). + * + * @param cubemap Cubemap representing the Irradiance pre-convolved by + * \f$ \langle n \cdot l \rangle \f$. + * + * @return This Builder, for chaining calls. + * + * @note + * This irradiance cubemap can be generated with the **cmgen** tool. + * + * @see irradiance(uint8_t bands, math::float3 const* sh) + */ + Builder& irradiance(Texture const* UTILS_NULLABLE cubemap) noexcept; + + /** + * (optional) Environment intensity. + * + * Because the environment is encoded usually relative to some reference, the + * range can be adjusted with this method. + * + * @param envIntensity Scale factor applied to the environment and irradiance such that + * the result is in lux, or lumen/m^2 (default = 30000) + * + * @return This Builder, for chaining calls. + */ + Builder& intensity(float envIntensity) noexcept; + + /** + * Specifies the rigid-body transformation to apply to the IBL. + * + * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. + * + * @return This Builder, for chaining calls. + */ + Builder& rotation(math::mat3f const& rotation) noexcept; + + /** + * Creates the IndirectLight object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this IndirectLight with. + * + * @return pointer to the newly created object or nullptr if exceptions are disabled and + * an error occurred. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + IndirectLight* UTILS_NONNULL build(Engine& engine); + + private: + friend class FIndirectLight; + }; + + /** + * Sets the environment's intensity. + * + * Because the environment is encoded usually relative to some reference, the + * range can be adjusted with this method. + * + * @param intensity Scale factor applied to the environment and irradiance such that + * the result is in lux, or lumen/m^2 (default = 30000) + */ + void setIntensity(float intensity) noexcept; + + /** + * Returns the environment's intensity in lux, or lumen/m^2. + */ + float getIntensity() const noexcept; + + /** + * Sets the rigid-body transformation to apply to the IBL. + * + * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. + */ + void setRotation(math::mat3f const& rotation) noexcept; + + /** + * Returns the rigid-body transformation applied to the IBL. + */ + const math::mat3f& getRotation() const noexcept; + + /** + * Returns the associated reflection map, or null if it does not exist. + */ + Texture const* UTILS_NULLABLE getReflectionsTexture() const noexcept; + + /** + * Returns the associated irradiance map, or null if it does not exist. + */ + Texture const* UTILS_NULLABLE getIrradianceTexture() const noexcept; + + /** + * Helper to estimate the direction of the dominant light in the environment represented by + * spherical harmonics. + * + * This assumes that there is only a single dominant light (such as the sun in outdoors + * environments), if it's not the case the direction returned will be an average of the + * various lights based on their intensity. + * + * If there are no clear dominant light, as is often the case with low dynamic range (LDR) + * environments, this method may return a wrong or unexpected direction. + * + * The dominant light direction can be used to set a directional light's direction, + * for instance to produce shadows that match the environment. + * + * @param sh 3-band spherical harmonics + * + * @return A unit vector representing the direction of the dominant light + * + * @see LightManager::Builder::direction() + * @see getColorEstimate() + */ + static math::float3 getDirectionEstimate(const math::float3 sh[UTILS_NONNULL 9]) noexcept; + + /** + * Helper to estimate the color and relative intensity of the environment represented by + * spherical harmonics in a given direction. + * + * This can be used to set the color and intensity of a directional light. In this case + * make sure to multiply this relative intensity by the the intensity of this indirect light. + * + * @param sh 3-band spherical harmonics + * @param direction a unit vector representing the direction of the light to estimate the + * color of. Typically this the value returned by getDirectionEstimate(). + * + * @return A vector of 4 floats where the first 3 components represent the linear color and + * the 4th component represents the intensity of the dominant light + * + * @see LightManager::Builder::color() + * @see LightManager::Builder::intensity() + * @see getDirectionEstimate, getIntensity, setIntensity + */ + static math::float4 getColorEstimate(const math::float3 sh[UTILS_NONNULL 9], + math::float3 direction) noexcept; + + + /** @deprecated use static versions instead */ + UTILS_DEPRECATED + math::float3 getDirectionEstimate() const noexcept; + + /** @deprecated use static versions instead */ + UTILS_DEPRECATED + math::float4 getColorEstimate(math::float3 direction) const noexcept; + +protected: + // prevent heap allocation + ~IndirectLight() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_INDIRECTLIGHT_H diff --git a/package/android/libs/filament/include/filament/InstanceBuffer.h b/package/android/libs/filament/include/filament/InstanceBuffer.h new file mode 100644 index 00000000..2135152d --- /dev/null +++ b/package/android/libs/filament/include/filament/InstanceBuffer.h @@ -0,0 +1,106 @@ +/* +* Copyright (C) 2023 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. +*/ + +#ifndef TNT_FILAMENT_INSTANCEBUFFER_H +#define TNT_FILAMENT_INSTANCEBUFFER_H + +#include +#include + +#include + +#include + +#include + +namespace filament { + +/** + * InstanceBuffer holds draw (GPU) instance transforms. These can be provided to a renderable to + * "offset" each draw instance. + * + * @see RenderableManager::Builder::instances(size_t, InstanceBuffer*) + */ +class UTILS_PUBLIC InstanceBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + + public: + + /** + * @param instanceCount the number of instances this InstanceBuffer will support, must be + * >= 1 and <= \c Engine::getMaxAutomaticInstances() + * @see Engine::getMaxAutomaticInstances + */ + explicit Builder(size_t instanceCount) noexcept; + + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Provide an initial local transform for each instance. Each local transform is relative to + * the transform of the associated renderable. This forms a parent-child relationship + * between the renderable and its instances, so adjusting the renderable's transform will +- * affect all instances. + * + * The array of math::mat4f must have length instanceCount, provided when constructing this + * Builder. + * + * @param localTransforms an array of math::mat4f with length instanceCount, must remain + * valid until after build() is called + */ + Builder& localTransforms(math::mat4f const* UTILS_NULLABLE localTransforms) noexcept; + + /** + * Creates the InstanceBuffer object and returns a pointer to it. + */ + InstanceBuffer* UTILS_NONNULL build(Engine& engine); + + private: + friend class FInstanceBuffer; + }; + + /** + * Returns the instance count specified when building this InstanceBuffer. + */ + size_t getInstanceCount() const noexcept; + + /** + * Sets the local transform for each instance. Each local transform is relative to the transform + * of the associated renderable. This forms a parent-child relationship between the renderable + * and its instances, so adjusting the renderable's transform will affect all instances. + * + * @param localTransforms an array of math::mat4f with length count, need not outlive this call + * @param count the number of local transforms + * @param offset index of the first instance to set local transforms + */ + void setLocalTransforms(math::mat4f const* UTILS_NONNULL localTransforms, + size_t count, size_t offset = 0); + +protected: + // prevent heap allocation + ~InstanceBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_INSTANCEBUFFER_H diff --git a/package/android/libs/filament/include/filament/LightManager.h b/package/android/libs/filament/include/filament/LightManager.h new file mode 100644 index 00000000..22d663f2 --- /dev/null +++ b/package/android/libs/filament/include/filament/LightManager.h @@ -0,0 +1,977 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_LIGHTMANAGER_H +#define TNT_FILAMENT_LIGHTMANAGER_H + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class Engine; +class FEngine; +class FLightManager; + +/** + * LightManager allows to create a light source in the scene, such as a sun or street lights. + * + * At least one light must be added to a scene in order to see anything + * (unless the Material.Shading.UNLIT is used). + * + * + * Creation and destruction + * ======================== + * + * A Light component is created using the LightManager::Builder and destroyed by calling + * LightManager::destroy(utils::Entity). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * utils::Entity sun = utils::EntityManager.get().create(); + * + * filament::LightManager::Builder(Type::SUN) + * .castShadows(true) + * .build(*engine, sun); + * + * engine->getLightManager().destroy(sun); + * ~~~~~~~~~~~ + * + * + * Light types + * =========== + * + * Lights come in three flavors: + * - directional lights + * - point lights + * - spot lights + * + * + * Directional lights + * ------------------ + * + * Directional lights have a direction, but don't have a position. All light rays are + * parallel and come from infinitely far away and from everywhere. Typically a directional light + * is used to simulate the sun. + * + * Directional lights and spot lights are able to cast shadows. + * + * To create a directional light use Type.DIRECTIONAL or Type.SUN, both are similar, but the later + * also draws a sun's disk in the sky and its reflection on glossy objects. + * + * @warning Currently, only a single directional light is supported. If several directional lights + * are added to the scene, the dominant one will be used. + * + * @see Builder.direction(), Builder.sunAngularRadius() + * + * Point lights + * ------------ + * + * Unlike directional lights, point lights have a position but emit light in all directions. + * The intensity of the light diminishes with the inverse square of the distance to the light. + * Builder.falloff() controls distance beyond which the light has no more influence. + * + * A scene can have multiple point lights. + * + * @see Builder.position(), Builder.falloff() + * + * Spot lights + * ----------- + * + * Spot lights are similar to point lights but the light it emits is limited to a cone defined by + * Builder.spotLightCone() and the light's direction. + * + * A spot light is therefore defined by a position, a direction and inner and outer cones. The + * spot light's influence is limited to inside the outer cone. The inner cone defines the light's + * falloff attenuation. + * + * A physically correct spot light is a little difficult to use because changing the outer angle + * of the cone changes the illumination levels, as the same amount of light is spread over a + * changing volume. The coupling of illumination and the outer cone means that an artist cannot + * tweak the influence cone of a spot light without also changing the perceived illumination. + * It therefore makes sense to provide artists with a parameter to disable this coupling. This + * is the difference between Type.FOCUSED_SPOT and Type.SPOT. + * + * @see Builder.position(), Builder.direction(), Builder.falloff(), Builder.spotLightCone() + * + * Performance considerations + * ========================== + * + * Generally, adding lights to the scene hurts performance, however filament is designed to be + * able to handle hundreds of lights in a scene under certain conditions. Here are some tips + * to keep performances high. + * + * 1. Prefer spot lights to point lights and use the smallest outer cone angle possible. + * + * 2. Use the smallest possible falloff distance for point and spot lights. + * Performance is very sensitive to overlapping lights. The falloff distance essentially + * defines a sphere of influence for the light, so try to position point and spot lights + * such that they don't overlap too much. + * + * On the other hand, a scene can contain hundreds of non overlapping lights without + * incurring a significant overhead. + * + */ +class UTILS_PUBLIC LightManager : public FilamentAPI { + struct BuilderDetails; + +public: + using Instance = utils::EntityInstance; + + /** + * Returns the number of component in the LightManager, note that component are not + * guaranteed to be active. Use the EntityManager::isAlive() before use if needed. + * + * @return number of component in the LightManager + */ + size_t getComponentCount() const noexcept; + + /** + * Returns whether a particular Entity is associated with a component of this LightManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * Gets an Instance representing the Light component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the Light component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(utils::Entity e) const noexcept; + + // destroys this component from the given entity + void destroy(utils::Entity e) noexcept; + + + //! Denotes the type of the light being created. + enum class Type : uint8_t { + SUN, //!< Directional light that also draws a sun's disk in the sky. + DIRECTIONAL, //!< Directional light, emits light in a given direction. + POINT, //!< Point light, emits light from a position, in all directions. + FOCUSED_SPOT, //!< Physically correct spot light. + SPOT, //!< Spot light with coupling of outer cone and illumination disabled. + }; + + /** + * Control the quality / performance of the shadow map associated to this light + */ + struct ShadowOptions { + /** Size of the shadow map in texels. Must be a power-of-two and larger or equal to 8. */ + uint32_t mapSize = 1024; + + /** + * Number of shadow cascades to use for this light. Must be between 1 and 4 (inclusive). + * A value greater than 1 turns on cascaded shadow mapping (CSM). + * Only applicable to Type.SUN or Type.DIRECTIONAL lights. + * + * When using shadow cascades, cascadeSplitPositions must also be set. + * + * @see ShadowOptions::cascadeSplitPositions + */ + uint8_t shadowCascades = 1; + + /** + * The split positions for shadow cascades. + * + * Cascaded shadow mapping (CSM) partitions the camera frustum into cascades. These values + * determine the planes along the camera's Z axis to split the frustum. The camera near + * plane is represented by 0.0f and the far plane represented by 1.0f. + * + * For example, if using 4 cascades, these values would set a uniform split scheme: + * { 0.25f, 0.50f, 0.75f } + * + * For N cascades, N - 1 split positions will be read from this array. + * + * Filament provides utility methods inside LightManager::ShadowCascades to help set these + * values. For example, to use a uniform split scheme: + * + * ~~~~~~~~~~~{.cpp} + * LightManager::ShadowCascades::computeUniformSplits(options.splitPositions, 4); + * ~~~~~~~~~~~ + * + * @see ShadowCascades::computeUniformSplits + * @see ShadowCascades::computeLogSplits + * @see ShadowCascades::computePracticalSplits + */ + float cascadeSplitPositions[3] = { 0.125f, 0.25f, 0.50f }; + + /** Constant bias in world units (e.g. meters) by which shadows are moved away from the + * light. 1mm by default. + * This is ignored when the View's ShadowType is set to VSM. + */ + float constantBias = 0.001f; + + /** Amount by which the maximum sampling error is scaled. The resulting value is used + * to move the shadow away from the fragment normal. Should be 1.0. + * This is ignored when the View's ShadowType is set to VSM. + */ + float normalBias = 1.0f; + + /** Distance from the camera after which shadows are clipped. This is used to clip + * shadows that are too far and wouldn't contribute to the scene much, improving + * performance and quality. This value is always positive. + * Use 0.0f to use the camera far distance. + * This only affect directional lights. + */ + float shadowFar = 0.0f; + + /** Optimize the quality of shadows from this distance from the camera. Shadows will + * be rendered in front of this distance, but the quality may not be optimal. + * This value is always positive. Use 0.0f to use the camera near distance. + * The default of 1m works well with many scenes. The quality of shadows may drop + * rapidly when this value decreases. + */ + float shadowNearHint = 1.0f; + + /** Optimize the quality of shadows in front of this distance from the camera. Shadows + * will be rendered behind this distance, but the quality may not be optimal. + * This value is always positive. Use std::numerical_limits::infinity() to + * use the camera far distance. + */ + float shadowFarHint = 100.0f; + + /** + * Controls whether the shadow map should be optimized for resolution or stability. + * When set to true, all resolution enhancing features that can affect stability are + * disabling, resulting in significantly lower resolution shadows, albeit stable ones. + * + * Setting this flag to true always disables LiSPSM (see below). + * + * @see lispsm + */ + bool stable = false; + + /** + * LiSPSM, or light-space perspective shadow-mapping is a technique allowing to better + * optimize the use of the shadow-map texture. When enabled the effective resolution of + * shadows is greatly improved and yields result similar to using cascades without the + * extra cost. LiSPSM comes with some drawbacks however, in particular it is incompatible + * with blurring because it effectively affects the blur kernel size. + * + * Blurring is only an issue when using ShadowType::VSM with a large blur or with + * ShadowType::PCSS however. + * + * If these blurring artifacts become problematic, this flag can be used to disable LiSPSM. + * + * @see stable + */ + bool lispsm = true; + + /** + * Constant bias in depth-resolution units by which shadows are moved away from the + * light. The default value of 0.5 is used to round depth values up. + * Generally this value shouldn't be changed or at least be small and positive. + * This is ignored when the View's ShadowType is set to VSM. + */ + float polygonOffsetConstant = 0.5f; + + /** + * Bias based on the change in depth in depth-resolution units by which shadows are moved + * away from the light. The default value of 2.0 works well with SHADOW_SAMPLING_PCF_LOW. + * Generally this value is between 0.5 and the size in texel of the PCF filter. + * Setting this value correctly is essential for LISPSM shadow-maps. + * This is ignored when the View's ShadowType is set to VSM. + */ + float polygonOffsetSlope = 2.0f; + + /** + * Whether screen-space contact shadows are used. This applies regardless of whether a + * Renderable is a shadow caster. + * Screen-space contact shadows are typically useful in large scenes. + * (off by default) + */ + bool screenSpaceContactShadows = false; + + /** + * Number of ray-marching steps for screen-space contact shadows (8 by default). + * + * CAUTION: this parameter is ignored for all lights except the directional/sun light, + * all other lights use the same value set for the directional/sun light. + * + */ + uint8_t stepCount = 8; + + /** + * Maximum shadow-occluder distance for screen-space contact shadows (world units). + * (30 cm by default) + * + * CAUTION: this parameter is ignored for all lights except the directional/sun light, + * all other lights use the same value set for the directional/sun light. + * + */ + float maxShadowDistance = 0.3f; + + /** + * Options available when the View's ShadowType is set to VSM. + * + * @warning This API is still experimental and subject to change. + * @see View::setShadowType + */ + struct Vsm { + /** + * When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is + * an improvement to the default EVSM which suffers important light leaks. Enabling + * ELVSM for a single shadowmap doubles the memory usage of all shadow maps. + * ELVSM is mostly useful when large blurs are used. + */ + bool elvsm = false; + + /** + * Blur width for the VSM blur. Zero do disable. + * The maximum value is 125. + */ + float blurWidth = 0.0f; + } vsm; + + /** + * Light bulb radius used for soft shadows. Currently this is only used when DPCF or PCSS is + * enabled. (2cm by default). + */ + float shadowBulbRadius = 0.02f; + + /** + * Transforms the shadow direction. Must be a unit quaternion. + * The default is identity. + * Ignored if the light type isn't directional. For artistic use. Use with caution. + */ + math::quatf transform{ 1.0f }; + }; + + struct ShadowCascades { + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a uniform + * split scheme. + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + */ + static void computeUniformSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades); + + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a logarithmic + * split scheme. + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + * @param near the camera near plane + * @param far the camera far plane + */ + static void computeLogSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades, + float near, float far); + + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a practical + * split scheme. + * + * The practical split scheme uses uses a lambda value to interpolate between the logarithmic + * and uniform split schemes. Start with a lambda value of 0.5f and adjust for your scene. + * + * See: Zhang et al 2006, "Parallel-split shadow maps for large-scale virtual environments" + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + * @param near the camera near plane + * @param far the camera far plane + * @param lambda a float in the range [0, 1] that interpolates between log and + * uniform split schemes + */ + static void computePracticalSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades, + float near, float far, float lambda); + }; + + //! Use Builder to construct a Light object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + /** + * Creates a light builder and set the light's #Type. + * + * @param type #Type of Light object to create. + */ + explicit Builder(Type type) noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * + * @param channel Light channel to enable or disable, between 0 and 7. + * @param enable Whether to enable or disable the light channel. + * @return This Builder, for chaining calls. + */ + Builder& lightChannel(unsigned int channel, bool enable = true) noexcept; + + /** + * Whether this Light casts shadows (disabled by default) + * + * @param enable Enables or disables casting shadows from this Light. + * + * @return This Builder, for chaining calls. + */ + Builder& castShadows(bool enable) noexcept; + + /** + * Sets the shadow-map options for this light. + * + * @return This Builder, for chaining calls. + */ + Builder& shadowOptions(const ShadowOptions& options) noexcept; + + /** + * Whether this light casts light (enabled by default) + * + * @param enable Enables or disables lighting from this Light. + * + * @return This Builder, for chaining calls. + * + * @note + * In some situations it can be useful to have a light in the scene that doesn't + * actually emit light, but does cast shadows. + */ + Builder& castLight(bool enable) noexcept; + + /** + * Sets the initial position of the light in world space. + * + * @param position Light's position in world space. The default is at the origin. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's position is ignored for directional lights (Type.DIRECTIONAL or Type.SUN) + */ + Builder& position(const math::float3& position) noexcept; + + /** + * Sets the initial direction of a light in world space. + * + * @param direction Light's direction in world space. Should be a unit vector. + * The default is {0,-1,0}. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's direction is ignored for Type.POINT lights. + */ + Builder& direction(const math::float3& direction) noexcept; + + /** + * Sets the initial color of a light. + * + * @param color Color of the light specified in the linear sRGB color-space. + * The default is white {1,1,1}. + * + * @return This Builder, for chaining calls. + */ + Builder& color(const LinearColor& color) noexcept; + + /** + * Sets the initial intensity of a light. + * @param intensity This parameter depends on the Light.Type: + * - For directional lights, it specifies the illuminance in *lux* + * (or *lumen/m^2*). + * - For point lights and spot lights, it specifies the luminous power + * in *lumen*. + * + * @return This Builder, for chaining calls. + * + * For example, the sun's illuminance is about 100,000 lux. + * + * This method overrides any prior calls to intensity or intensityCandela. + * + */ + Builder& intensity(float intensity) noexcept; + + /** + * Sets the initial intensity of a spot or point light in candela. + * + * @param intensity Luminous intensity in *candela*. + * + * @return This Builder, for chaining calls. + * + * @note + * This method is equivalent to calling intensity(float intensity) for directional lights + * (Type.DIRECTIONAL or Type.SUN). + * + * This method overrides any prior calls to intensity or intensityCandela. + */ + Builder& intensityCandela(float intensity) noexcept; + + /** + * Sets the initial intensity of a light in watts. + * + * @param watts Energy consumed by a lightbulb. It is related to the energy produced + * and ultimately the brightness by the \p efficiency parameter. + * This value is often available on the packaging of commercial + * lightbulbs. + * + * @param efficiency Efficiency in percent. This depends on the type of lightbulb used. + * + * Lightbulb type | Efficiency + * ----------------:|-----------: + * Incandescent | 2.2% + * Halogen | 7.0% + * LED | 8.7% + * Fluorescent | 10.7% + * + * @return This Builder, for chaining calls. + * + * + * @note + * This call is equivalent to `Builder::intensity(efficiency * 683 * watts);` + * + * This method overrides any prior calls to intensity or intensityCandela. + */ + Builder& intensity(float watts, float efficiency) noexcept; + + /** + * Set the falloff distance for point lights and spot lights. + * + * At the falloff distance, the light has no more effect on objects. + * + * The falloff distance essentially defines a *sphere of influence* around the light, and + * therefore has an impact on performance. Larger falloffs might reduce performance + * significantly, especially when many lights are used. + * + * Try to avoid having a large number of light's spheres of influence overlap. + * + * @param radius Falloff distance in world units. Default is 1 meter. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's falloff is ignored for directional lights (Type.DIRECTIONAL or Type.SUN) + */ + Builder& falloff(float radius) noexcept; + + /** + * Defines a spot light'st angular falloff attenuation. + * + * A spot light is defined by a position, a direction and two cones, \p inner and \p outer. + * These two cones are used to define the angular falloff attenuation of the spot light + * and are defined by the angle from the center axis to where the falloff begins (i.e. + * cones are defined by their half-angle). + * + * Both inner and outer are silently clamped to a minimum value of 0.5 degrees + * (~0.00873 radians) to avoid floating-point precision issues during rendering. + * + * @param inner inner cone angle in *radians* between 0.00873 and \p outer + * @param outer outer cone angle in *radians* between 0.00873 inner and @f$ \pi/2 @f$ + * @return This Builder, for chaining calls. + * + * @note + * The spot light cone is ignored for directional and point lights. + * + * @see Type.SPOT, Type.FOCUSED_SPOT + */ + Builder& spotLightCone(float inner, float outer) noexcept; + + /** + * Defines the angular radius of the sun, in degrees, between 0.25° and 20.0° + * + * The Sun as seen from Earth has an angular size of 0.526° to 0.545° + * + * @param angularRadius sun's radius in degree. Default is 0.545°. + * + * @return This Builder, for chaining calls. + */ + Builder& sunAngularRadius(float angularRadius) noexcept; + + /** + * Defines the halo radius of the sun. The radius of the halo is defined as a + * multiplier of the sun angular radius. + * + * @param haloSize radius multiplier. Default is 10.0. + * + * @return This Builder, for chaining calls. + */ + Builder& sunHaloSize(float haloSize) noexcept; + + /** + * Defines the halo falloff of the sun. The falloff is a dimensionless number + * used as an exponent. + * + * @param haloFalloff halo falloff. Default is 80.0. + * + * @return This Builder, for chaining calls. + */ + Builder& sunHaloFalloff(float haloFalloff) noexcept; + + enum Result { Error = -1, Success = 0 }; + + /** + * Adds the Light component to an entity. + * + * @param engine Reference to the filament::Engine to associate this light with. + * @param entity Entity to add the light component to. + * @return Success if the component was created successfully, Error otherwise. + * + * If exceptions are disabled and an error occurs, this function is a no-op. + * Success can be checked by looking at the return value. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(utils::Entity e) was called. + * + * @warning + * Currently, only 2048 lights can be created on a given Engine. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Result build(Engine& engine, utils::Entity entity); + + private: + friend class FEngine; + friend class FLightManager; + }; + + static constexpr float EFFICIENCY_INCANDESCENT = 0.0220f; //!< Typical efficiency of an incandescent light bulb (2.2%) + static constexpr float EFFICIENCY_HALOGEN = 0.0707f; //!< Typical efficiency of an halogen light bulb (7.0%) + static constexpr float EFFICIENCY_FLUORESCENT = 0.0878f; //!< Typical efficiency of a fluorescent light bulb (8.7%) + static constexpr float EFFICIENCY_LED = 0.1171f; //!< Typical efficiency of a LED light bulb (11.7%) + + Type getType(Instance i) const noexcept; + + /** + * Helper function that returns if a light is a directional light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of directional light + */ + inline bool isDirectional(Instance i) const noexcept { + Type const type = getType(i); + return type == Type::DIRECTIONAL || type == Type::SUN; + } + + /** + * Helper function that returns if a light is a point light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of point light + */ + inline bool isPointLight(Instance i) const noexcept { + return getType(i) == Type::POINT; + } + + /** + * Helper function that returns if a light is a spot light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of spot light + */ + inline bool isSpotLight(Instance i) const noexcept { + Type const type = getType(i); + return type == Type::SPOT || type == Type::FOCUSED_SPOT; + } + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * @param channel light channel to enable or disable, between 0 and 7. + * @param enable whether to enable (true) or disable (false) the specified light channel. + */ + void setLightChannel(Instance i, unsigned int channel, bool enable = true) noexcept; + + /** + * Returns whether a light channel is enabled on a specified light. + * @param i Instance of the component obtained from getInstance(). + * @param channel Light channel to query + * @return true if the light channel is enabled, false otherwise + */ + bool getLightChannel(Instance i, unsigned int channel) const noexcept; + + /** + * Dynamically updates the light's position. + * + * @param i Instance of the component obtained from getInstance(). + * @param position Light's position in world space. The default is at the origin. + * + * @see Builder.position() + */ + void setPosition(Instance i, const math::float3& position) noexcept; + + //! returns the light's position in world space + const math::float3& getPosition(Instance i) const noexcept; + + /** + * Dynamically updates the light's direction + * + * @param i Instance of the component obtained from getInstance(). + * @param direction Light's direction in world space. Should be a unit vector. + * The default is {0,-1,0}. + * + * @see Builder.direction() + */ + void setDirection(Instance i, const math::float3& direction) noexcept; + + //! returns the light's direction in world space + const math::float3& getDirection(Instance i) const noexcept; + + /** + * Dynamically updates the light's hue as linear sRGB + * + * @param i Instance of the component obtained from getInstance(). + * @param color Color of the light specified in the linear sRGB color-space. + * The default is white {1,1,1}. + * + * @see Builder.color(), getInstance() + */ + void setColor(Instance i, const LinearColor& color) noexcept; + + /** + * @param i Instance of the component obtained from getInstance(). + * @return the light's color in linear sRGB + */ + const math::float3& getColor(Instance i) const noexcept; + + /** + * Dynamically updates the light's intensity. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param intensity This parameter depends on the Light.Type: + * - For directional lights, it specifies the illuminance in *lux* + * (or *lumen/m^2*). + * - For point lights and spot lights, it specifies the luminous power + * in *lumen*. + * + * @see Builder.intensity() + */ + void setIntensity(Instance i, float intensity) noexcept; + + /** + * Dynamically updates the light's intensity. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param watts Energy consumed by a lightbulb. It is related to the energy produced + * and ultimately the brightness by the \p efficiency parameter. + * This value is often available on the packaging of commercial + * lightbulbs. + * @param efficiency Efficiency in percent. This depends on the type of lightbulb used. + * + * Lightbulb type | Efficiency + * ----------------:|-----------: + * Incandescent | 2.2% + * Halogen | 7.0% + * LED | 8.7% + * Fluorescent | 10.7% + * + * @see Builder.intensity(float watts, float efficiency) + */ + void setIntensity(Instance i, float watts, float efficiency) noexcept { + setIntensity(i, watts * 683.0f * efficiency); + } + + /** + * Dynamically updates the light's intensity in candela. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param intensity Luminous intensity in *candela*. + * + * @note + * This method is equivalent to calling setIntensity(float intensity) for directional lights + * (Type.DIRECTIONAL or Type.SUN). + * + * @see Builder.intensityCandela(float intensity) + */ + void setIntensityCandela(Instance i, float intensity) noexcept; + + /** + * returns the light's luminous intensity in candela. + * + * @param i Instance of the component obtained from getInstance(). + * + * @note for Type.FOCUSED_SPOT lights, the returned value depends on the \p outer cone angle. + * + * @return luminous intensity in candela. + */ + float getIntensity(Instance i) const noexcept; + + /** + * Set the falloff distance for point lights and spot lights. + * + * @param i Instance of the component obtained from getInstance(). + * @param radius falloff distance in world units. Default is 1 meter. + * + * @see Builder.falloff() + */ + void setFalloff(Instance i, float radius) noexcept; + + /** + * returns the falloff distance of this light. + * @param i Instance of the component obtained from getInstance(). + * @return the falloff distance of this light. + */ + float getFalloff(Instance i) const noexcept; + + /** + * Dynamically updates a spot light's cone as angles + * + * @param i Instance of the component obtained from getInstance(). + * @param inner inner cone angle in *radians* between 0.00873 and outer + * @param outer outer cone angle in *radians* between 0.00873 and pi/2 + * + * @see Builder.spotLightCone() + */ + void setSpotLightCone(Instance i, float inner, float outer) noexcept; + + /** + * returns the outer cone angle in *radians* between inner and pi/2. + * @param i Instance of the component obtained from getInstance(). + * @return the outer cone angle of this light. + */ + float getSpotLightOuterCone(Instance i) const noexcept; + + /** + * returns the inner cone angle in *radians* between 0 and pi/2. + * + * The value is recomputed from the initial values, thus is not precisely + * the same as the one passed to setSpotLightCone() or Builder.spotLightCone(). + * + * @param i Instance of the component obtained from getInstance(). + * @return the inner cone angle of this light. + */ + float getSpotLightInnerCone(Instance i) const noexcept; + + /** + * Dynamically updates the angular radius of a Type.SUN light + * + * The Sun as seen from Earth has an angular size of 0.526° to 0.545° + * + * @param i Instance of the component obtained from getInstance(). + * @param angularRadius sun's radius in degrees. Default is 0.545°. + */ + void setSunAngularRadius(Instance i, float angularRadius) noexcept; + + /** + * returns the angular radius if the sun in degrees. + * @param i Instance of the component obtained from getInstance(). + * @return the angular radius if the sun in degrees. + */ + float getSunAngularRadius(Instance i) const noexcept; + + /** + * Dynamically updates the halo radius of a Type.SUN light. The radius + * of the halo is defined as a multiplier of the sun angular radius. + * + * @param i Instance of the component obtained from getInstance(). + * @param haloSize radius multiplier. Default is 10.0. + */ + void setSunHaloSize(Instance i, float haloSize) noexcept; + + /** + * returns the halo size of a Type.SUN light as a multiplier of the + * sun angular radius. + * @param i Instance of the component obtained from getInstance(). + * @return the halo size + */ + float getSunHaloSize(Instance i) const noexcept; + + /** + * Dynamically updates the halo falloff of a Type.SUN light. The falloff + * is a dimensionless number used as an exponent. + * + * @param i Instance of the component obtained from getInstance(). + * @param haloFalloff halo falloff. Default is 80.0. + */ + void setSunHaloFalloff(Instance i, float haloFalloff) noexcept; + + /** + * returns the halo falloff of a Type.SUN light as a dimensionless value. + * @param i Instance of the component obtained from getInstance(). + * @return the halo falloff + */ + float getSunHaloFalloff(Instance i) const noexcept; + + /** + * returns the shadow-map options for a given light + * @param i Instance of the component obtained from getInstance(). + * @return A ShadowOption structure + */ + ShadowOptions const& getShadowOptions(Instance i) const noexcept; + + /** + * sets the shadow-map options for a given light + * @param i Instance of the component obtained from getInstance(). + * @param options A ShadowOption structure + */ + void setShadowOptions(Instance i, ShadowOptions const& options) noexcept; + + /** + * Whether this Light casts shadows (disabled by default) + * + * @param i Instance of the component obtained from getInstance(). + * @param shadowCaster Enables or disables casting shadows from this Light. + * + * @warning + * - Only a Type.DIRECTIONAL, Type.SUN, Type.SPOT, or Type.FOCUSED_SPOT light can cast shadows + */ + void setShadowCaster(Instance i, bool shadowCaster) noexcept; + + /** + * returns whether this light casts shadows. + * @param i Instance of the component obtained from getInstance(). + */ + bool isShadowCaster(Instance i) const noexcept; + +protected: + // prevent heap allocation + ~LightManager() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_LIGHTMANAGER_H diff --git a/package/android/libs/filament/include/filament/Material.h b/package/android/libs/filament/include/filament/Material.h new file mode 100644 index 00000000..b4b9bbed --- /dev/null +++ b/package/android/libs/filament/include/filament/Material.h @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_MATERIAL_H +#define TNT_FILAMENT_MATERIAL_H + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +namespace utils { + class CString; +} // namespace utils + +namespace filament { + +class Texture; +class TextureSampler; + +class FEngine; +class FMaterial; + +class Engine; + +class UTILS_PUBLIC Material : public FilamentAPI { + struct BuilderDetails; + +public: + using BlendingMode = filament::BlendingMode; + using Shading = filament::Shading; + using Interpolation = filament::Interpolation; + using VertexDomain = filament::VertexDomain; + using TransparencyMode = filament::TransparencyMode; + + using ParameterType = backend::UniformType; + using Precision = backend::Precision; + using SamplerType = backend::SamplerType; + using SamplerFormat = backend::SamplerFormat; + using CullingMode = backend::CullingMode; + using ShaderModel = backend::ShaderModel; + using SubpassType = backend::SubpassType; + + /** + * Holds information about a material parameter. + */ + struct ParameterInfo { + //! Name of the parameter. + const char* UTILS_NONNULL name; + //! Whether the parameter is a sampler (texture). + bool isSampler; + //! Whether the parameter is a subpass type. + bool isSubpass; + union { + //! Type of the parameter if the parameter is not a sampler. + ParameterType type; + //! Type of the parameter if the parameter is a sampler. + SamplerType samplerType; + //! Type of the parameter if the parameter is a subpass. + SubpassType subpassType; + }; + //! Size of the parameter when the parameter is an array. + uint32_t count; + //! Requested precision of the parameter. + Precision precision; + }; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Specifies the material data. The material data is a binary blob produced by + * libfilamat or by matc. + * + * @param payload Pointer to the material data, must stay valid until build() is called. + * @param size Size of the material data pointed to by "payload" in bytes. + */ + Builder& package(const void* UTILS_NONNULL payload, size_t size); + + template + using is_supported_constant_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + + /** + * Specialize a constant parameter specified in the material definition with a concrete + * value for this material. Once build() is called, this constant cannot be changed. + * Will throw an exception if the name does not match a constant specified in the + * material definition or if the type provided does not match. + * + * @tparam T The type of constant parameter, either int32_t, float, or bool. + * @param name The name of the constant parameter specified in the material definition, such + * as "myConstant". + * @param nameLength Length in `char` of the name parameter. + * @param value The value to use for the constant parameter, must match the type specified + * in the material definition. + */ + template> + Builder& constant(const char* UTILS_NONNULL name, size_t nameLength, T value); + + /** inline helper to provide the constant name as a null-terminated C string */ + template> + inline Builder& constant(const char* UTILS_NONNULL name, T value) { + return constant(name, strlen(name), value); + } + + /** + * Creates the Material object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Material with. + * + * @return pointer to the newly created object or nullptr if exceptions are disabled and + * an error occurred. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Material* UTILS_NULLABLE build(Engine& engine); + private: + friend class FMaterial; + }; + + using CompilerPriorityQueue = backend:: CompilerPriorityQueue; + + /** + * Asynchronously ensures that a subset of this Material's variants are compiled. After issuing + * several Material::compile() calls in a row, it is recommended to call Engine::flush() + * such that the backend can start the compilation work as soon as possible. + * The provided callback is guaranteed to be called on the main thread after all specified + * variants of the material are compiled. This can take hundreds of milliseconds. + * + * If all the material's variants are already compiled, the callback will be scheduled as + * soon as possible, but this might take a few dozen millisecond, corresponding to how + * many previous frames are enqueued in the backend. This also varies by backend. Therefore, + * it is recommended to only call this method once per material shortly after creation. + * + * If the same variant is scheduled for compilation multiple times, the first scheduling + * takes precedence; later scheduling are ignored. + * + * caveat: A consequence is that if a variant is scheduled on the low priority queue and later + * scheduled again on the high priority queue, the later scheduling is ignored. + * Therefore, the second callback could be called before the variant is compiled. + * However, the first callback, if specified, will trigger as expected. + * + * The callback is guaranteed to be called. If the engine is destroyed while some material + * variants are still compiling or in the queue, these will be discarded and the corresponding + * callback will be called. In that case however the Material pointer passed to the callback + * is guaranteed to be invalid (either because it's been destroyed by the user already, or, + * because it's been cleaned-up by the Engine). + * + * UserVariantFilterMask::ALL should be used with caution. Only variants that an application + * needs should be included in the variants argument. For example, the STE variant is only used + * for stereoscopic rendering. If an application is not planning to render in stereo, this bit + * should be turned off to avoid unnecessary material compilations. + * + * @param priority Which priority queue to use, LOW or HIGH. + * @param variants Variants to include to the compile command. + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback callback called on the main thread when the compilation is done on + * by backend. + */ + void compile(CompilerPriorityQueue priority, + UserVariantFilterMask variants, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept; + + inline void compile(CompilerPriorityQueue priority, + UserVariantFilterBit variants, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept { + compile(priority, UserVariantFilterMask(variants), handler, + std::forward>(callback)); + } + + inline void compile(CompilerPriorityQueue priority, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept { + compile(priority, UserVariantFilterBit::ALL, handler, + std::forward>(callback)); + } + + /** + * Creates a new instance of this material. Material instances should be freed using + * Engine::destroy(const MaterialInstance*). + * + * @param name Optional name to associate with the given material instance. If this is null, + * then the instance inherits the material's name. + * + * @return A pointer to the new instance. + */ + MaterialInstance* UTILS_NONNULL createInstance(const char* UTILS_NULLABLE name = nullptr) const noexcept; + + //! Returns the name of this material as a null-terminated string. + const char* UTILS_NONNULL getName() const noexcept; + + //! Returns the shading model of this material. + Shading getShading() const noexcept; + + //! Returns the interpolation mode of this material. This affects how variables are interpolated. + Interpolation getInterpolation() const noexcept; + + //! Returns the blending mode of this material. + BlendingMode getBlendingMode() const noexcept; + + //! Returns the vertex domain of this material. + VertexDomain getVertexDomain() const noexcept; + + //! Returns the material's supported variants + UserVariantFilterMask getSupportedVariants() const noexcept; + + //! Returns the material domain of this material. + //! The material domain determines how the material is used. + MaterialDomain getMaterialDomain() const noexcept; + + //! Returns the default culling mode of this material. + CullingMode getCullingMode() const noexcept; + + //! Returns the transparency mode of this material. + //! This value only makes sense when the blending mode is transparent or fade. + TransparencyMode getTransparencyMode() const noexcept; + + //! Indicates whether instances of this material will, by default, write to the color buffer. + bool isColorWriteEnabled() const noexcept; + + //! Indicates whether instances of this material will, by default, write to the depth buffer. + bool isDepthWriteEnabled() const noexcept; + + //! Indicates whether instances of this material will, by default, use depth testing. + bool isDepthCullingEnabled() const noexcept; + + //! Indicates whether this material is double-sided. + bool isDoubleSided() const noexcept; + + //! Indicates whether this material uses alpha to coverage. + bool isAlphaToCoverageEnabled() const noexcept; + + //! Returns the alpha mask threshold used when the blending mode is set to masked. + float getMaskThreshold() const noexcept; + + //! Indicates whether this material uses the shadowing factor as a color multiplier. + //! This values only makes sense when the shading mode is unlit. + bool hasShadowMultiplier() const noexcept; + + //! Indicates whether this material has specular anti-aliasing enabled + bool hasSpecularAntiAliasing() const noexcept; + + //! Returns the screen-space variance for specular-antialiasing, this value is between 0 and 1. + float getSpecularAntiAliasingVariance() const noexcept; + + //! Returns the clamping threshold for specular-antialiasing, this value is between 0 and 1. + float getSpecularAntiAliasingThreshold() const noexcept; + + //! Returns the list of vertex attributes required by this material. + AttributeBitset getRequiredAttributes() const noexcept; + + //! Returns the refraction mode used by this material. + RefractionMode getRefractionMode() const noexcept; + + //! Return the refraction type used by this material. + RefractionType getRefractionType() const noexcept; + + //! Returns the reflection mode used by this material. + ReflectionMode getReflectionMode() const noexcept; + + //! Returns the minimum required feature level for this material. + backend::FeatureLevel getFeatureLevel() const noexcept; + + /** + * Returns the number of parameters declared by this material. + * The returned value can be 0. + */ + size_t getParameterCount() const noexcept; + + /** + * Gets information about this material's parameters. + * + * @param parameters A pointer to a list of ParameterInfo. + * The list must be at least "count" large + * @param count The number of parameters to retrieve. Must be >= 0 and can be > count. + * + * @return The number of parameters written to the parameters pointer. + */ + size_t getParameters(ParameterInfo* UTILS_NONNULL parameters, size_t count) const noexcept; + + //! Indicates whether a parameter of the given name exists on this material. + bool hasParameter(const char* UTILS_NONNULL name) const noexcept; + + //! Indicates whether an existing parameter is a sampler or not. + bool isSampler(const char* UTILS_NONNULL name) const noexcept; + + /** + * Sets the value of the given parameter on this material's default instance. + * + * @param name The name of the material parameter + * @param value The value of the material parameter + * + * @see getDefaultInstance() + */ + template + void setDefaultParameter(const char* UTILS_NONNULL name, T value) noexcept { + getDefaultInstance()->setParameter(name, value); + } + + /** + * Sets a texture and sampler parameters on this material's default instance. + * + * @param name The name of the material texture parameter + * @param texture The texture to set as parameter + * @param sampler The sampler to be used with this texture + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) noexcept { + getDefaultInstance()->setParameter(name, texture, sampler); + } + + /** + * Sets the color of the given parameter on this material's default instance. + * + * @param name The name of the material color parameter + * @param type Whether the color is specified in the linear or sRGB space + * @param color The color as a floating point red, green, blue tuple + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) noexcept { + getDefaultInstance()->setParameter(name, type, color); + } + + /** + * Sets the color of the given parameter on this material's default instance. + * + * @param name The name of the material color parameter + * @param type Whether the color is specified in the linear or sRGB space + * @param color The color as a floating point red, green, blue, alpha tuple + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) noexcept { + getDefaultInstance()->setParameter(name, type, color); + } + + //! Returns this material's default instance. + MaterialInstance* UTILS_NONNULL getDefaultInstance() noexcept; + + //! Returns this material's default instance. + MaterialInstance const* UTILS_NONNULL getDefaultInstance() const noexcept; + +protected: + // prevent heap allocation + ~Material() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_MATERIAL_H diff --git a/package/android/libs/filament/include/filament/MaterialChunkType.h b/package/android/libs/filament/include/filament/MaterialChunkType.h new file mode 100644 index 00000000..6cff2003 --- /dev/null +++ b/package/android/libs/filament/include/filament/MaterialChunkType.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H +#define TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H + +#include + +#include + +namespace filamat { + +// Pack an eight character string into a 64 bit integer. +constexpr inline uint64_t charTo64bitNum(const char str[9]) noexcept { + return + ( (static_cast(str[0]) << 56)) + | ((static_cast(str[1]) << 48) & 0x00FF000000000000U) + | ((static_cast(str[2]) << 40) & 0x0000FF0000000000U) + | ((static_cast(str[3]) << 32) & 0x000000FF00000000U) + | ((static_cast(str[4]) << 24) & 0x00000000FF000000U) + | ((static_cast(str[5]) << 16) & 0x0000000000FF0000U) + | ((static_cast(str[6]) << 8) & 0x000000000000FF00U) + | ( static_cast(str[7]) & 0x00000000000000FFU); +} + +enum UTILS_PUBLIC ChunkType : uint64_t { + Unknown = charTo64bitNum("UNKNOWN "), + MaterialUib = charTo64bitNum("MAT_UIB "), + MaterialSib = charTo64bitNum("MAT_SIB "), + MaterialSubpass = charTo64bitNum("MAT_SUB "), + MaterialGlsl = charTo64bitNum("MAT_GLSL"), + MaterialEssl1 = charTo64bitNum("MAT_ESS1"), + MaterialSpirv = charTo64bitNum("MAT_SPIR"), + MaterialMetal = charTo64bitNum("MAT_METL"), + MaterialShaderModels = charTo64bitNum("MAT_SMDL"), + MaterialSamplerBindings = charTo64bitNum("MAT_SAMP"), + MaterialUniformBindings = charTo64bitNum("MAT_UNIF"), + MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"), + MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"), + MaterialProperties = charTo64bitNum("MAT_PROP"), + MaterialConstants = charTo64bitNum("MAT_CONS"), + + MaterialName = charTo64bitNum("MAT_NAME"), + MaterialVersion = charTo64bitNum("MAT_VERS"), + MaterialCacheId = charTo64bitNum("MAT_UUID"), + MaterialFeatureLevel = charTo64bitNum("MAT_FEAT"), + MaterialShading = charTo64bitNum("MAT_SHAD"), + MaterialBlendingMode = charTo64bitNum("MAT_BLEN"), + MaterialTransparencyMode = charTo64bitNum("MAT_TRMD"), + MaterialMaskThreshold = charTo64bitNum("MAT_THRS"), + MaterialShadowMultiplier = charTo64bitNum("MAT_SHML"), + MaterialSpecularAntiAliasing = charTo64bitNum("MAT_SPAA"), + MaterialSpecularAntiAliasingVariance = charTo64bitNum("MAT_SVAR"), + MaterialSpecularAntiAliasingThreshold = charTo64bitNum("MAT_STHR"), + MaterialClearCoatIorChange = charTo64bitNum("MAT_CIOR"), + MaterialDomain = charTo64bitNum("MAT_DOMN"), + MaterialVariantFilterMask = charTo64bitNum("MAT_VFLT"), + MaterialRefraction = charTo64bitNum("MAT_REFM"), + MaterialRefractionType = charTo64bitNum("MAT_REFT"), + MaterialReflectionMode = charTo64bitNum("MAT_REFL"), + + MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"), + MaterialDoubleSidedSet = charTo64bitNum("MAT_DOSS"), + MaterialDoubleSided = charTo64bitNum("MAT_DOSI"), + + MaterialColorWrite = charTo64bitNum("MAT_CWRIT"), + MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"), + MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"), + MaterialDepthTest = charTo64bitNum("MAT_DTEST"), + MaterialInstanced = charTo64bitNum("MAT_INSTA"), + MaterialCullingMode = charTo64bitNum("MAT_CUMO"), + MaterialAlphaToCoverageSet = charTo64bitNum("MAT_A2CS"), + MaterialAlphaToCoverage = charTo64bitNum("MAT_A2CO"), + + MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"), + + MaterialVertexDomain = charTo64bitNum("MAT_VEDO"), + MaterialInterpolation = charTo64bitNum("MAT_INTR"), + + DictionaryText = charTo64bitNum("DIC_TEXT"), + DictionarySpirv = charTo64bitNum("DIC_SPIR"), +}; + +} // namespace filamat + +#endif // TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H diff --git a/package/android/libs/filament/include/filament/MaterialEnums.h b/package/android/libs/filament/include/filament/MaterialEnums.h new file mode 100644 index 00000000..f98c707e --- /dev/null +++ b/package/android/libs/filament/include/filament/MaterialEnums.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_MATERIAL_ENUM_H +#define TNT_FILAMENT_MATERIAL_ENUM_H + +#include +#include + +#include +#include + +namespace filament { + +// update this when a new version of filament wouldn't work with older materials +static constexpr size_t MATERIAL_VERSION = 50; + +/** + * Supported shading models + */ +enum class Shading : uint8_t { + UNLIT, //!< no lighting applied, emissive possible + LIT, //!< default, standard lighting + SUBSURFACE, //!< subsurface lighting model + CLOTH, //!< cloth lighting model + SPECULAR_GLOSSINESS, //!< legacy lighting model +}; + +/** + * Attribute interpolation types in the fragment shader + */ +enum class Interpolation : uint8_t { + SMOOTH, //!< default, smooth interpolation + FLAT //!< flat interpolation +}; + +/** + * Shader quality, affect some global quality parameters + */ +enum class ShaderQuality : int8_t { + DEFAULT = -1, // LOW on mobile, HIGH on desktop + LOW = 0, // enable optimizations that can slightly affect correctness + NORMAL = 1, // normal quality, correctness honored + HIGH = 2 // higher quality (e.g. better upscaling, etc...) +}; + +/** + * Supported blending modes + */ +enum class BlendingMode : uint8_t { + //! material is opaque + OPAQUE, + //! material is transparent and color is alpha-pre-multiplied, affects diffuse lighting only + TRANSPARENT, + //! material is additive (e.g.: hologram) + ADD, + //! material is masked (i.e. alpha tested) + MASKED, + /** + * material is transparent and color is alpha-pre-multiplied, affects specular lighting + * when adding more entries, change the size of FRenderer::CommandKey::blending + */ + FADE, + //! material darkens what's behind it + MULTIPLY, + //! material brightens what's behind it + SCREEN, +}; + +/** + * How transparent objects are handled + */ +enum class TransparencyMode : uint8_t { + //! the transparent object is drawn honoring the raster state + DEFAULT, + /** + * the transparent object is first drawn in the depth buffer, + * then in the color buffer, honoring the culling mode, but ignoring the depth test function + */ + TWO_PASSES_ONE_SIDE, + + /** + * the transparent object is drawn twice in the color buffer, + * first with back faces only, then with front faces; the culling + * mode is ignored. Can be combined with two-sided lighting + */ + TWO_PASSES_TWO_SIDES +}; + +/** + * Supported types of vertex domains. + */ +enum class VertexDomain : uint8_t { + OBJECT, //!< vertices are in object space, default + WORLD, //!< vertices are in world space + VIEW, //!< vertices are in view space + DEVICE //!< vertices are in normalized device space + // when adding more entries, make sure to update VERTEX_DOMAIN_COUNT +}; + +/** + * Vertex attribute types + */ +enum VertexAttribute : uint8_t { + // Update hasIntegerTarget() in VertexBuffer when adding an attribute that will + // be read as integers in the shaders + + POSITION = 0, //!< XYZ position (float3) + TANGENTS = 1, //!< tangent, bitangent and normal, encoded as a quaternion (float4) + COLOR = 2, //!< vertex color (float4) + UV0 = 3, //!< texture coordinates (float2) + UV1 = 4, //!< texture coordinates (float2) + BONE_INDICES = 5, //!< indices of 4 bones, as unsigned integers (uvec4) + BONE_WEIGHTS = 6, //!< weights of the 4 bones (normalized float4) + // -- we have 1 unused slot here -- + CUSTOM0 = 8, + CUSTOM1 = 9, + CUSTOM2 = 10, + CUSTOM3 = 11, + CUSTOM4 = 12, + CUSTOM5 = 13, + CUSTOM6 = 14, + CUSTOM7 = 15, + + // Aliases for legacy vertex morphing. + // See RenderableManager::Builder::morphing(). + MORPH_POSITION_0 = CUSTOM0, + MORPH_POSITION_1 = CUSTOM1, + MORPH_POSITION_2 = CUSTOM2, + MORPH_POSITION_3 = CUSTOM3, + MORPH_TANGENTS_0 = CUSTOM4, + MORPH_TANGENTS_1 = CUSTOM5, + MORPH_TANGENTS_2 = CUSTOM6, + MORPH_TANGENTS_3 = CUSTOM7, + + // this is limited by driver::MAX_VERTEX_ATTRIBUTE_COUNT +}; + +static constexpr size_t MAX_LEGACY_MORPH_TARGETS = 4; +static constexpr size_t MAX_MORPH_TARGETS = 256; // this is limited by filament::CONFIG_MAX_MORPH_TARGET_COUNT +static constexpr size_t MAX_CUSTOM_ATTRIBUTES = 8; + +/** + * Material domains + */ +enum class MaterialDomain : uint8_t { + SURFACE = 0, //!< shaders applied to renderables + POST_PROCESS = 1, //!< shaders applied to rendered buffers + COMPUTE = 2, //!< compute shader +}; + +/** + * Specular occlusion + */ +enum class SpecularAmbientOcclusion : uint8_t { + NONE = 0, //!< no specular occlusion + SIMPLE = 1, //!< simple specular occlusion + BENT_NORMALS = 2, //!< more accurate specular occlusion, requires bent normals +}; + +/** + * Refraction + */ +enum class RefractionMode : uint8_t { + NONE = 0, //!< no refraction + CUBEMAP = 1, //!< refracted rays go to the ibl cubemap + SCREEN_SPACE = 2, //!< refracted rays go to screen space +}; + +/** + * Refraction type + */ +enum class RefractionType : uint8_t { + SOLID = 0, //!< refraction through solid objects (e.g. a sphere) + THIN = 1, //!< refraction through thin objects (e.g. window) +}; + +/** + * Reflection mode + */ +enum class ReflectionMode : uint8_t { + DEFAULT = 0, //! reflections sample from the scene's IBL only + SCREEN_SPACE = 1, //! reflections sample from screen space, and fallback to the scene's IBL +}; + +// can't really use std::underlying_type::type because the driver takes a uint32_t +using AttributeBitset = utils::bitset32; + +static constexpr size_t MATERIAL_PROPERTIES_COUNT = 26; +enum class Property : uint8_t { + BASE_COLOR, //!< float4, all shading models + ROUGHNESS, //!< float, lit shading models only + METALLIC, //!< float, all shading models, except unlit and cloth + REFLECTANCE, //!< float, all shading models, except unlit and cloth + AMBIENT_OCCLUSION, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT_ROUGHNESS, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT_NORMAL, //!< float, lit shading models only, except subsurface and cloth + ANISOTROPY, //!< float, lit shading models only, except subsurface and cloth + ANISOTROPY_DIRECTION, //!< float3, lit shading models only, except subsurface and cloth + THICKNESS, //!< float, subsurface shading model only + SUBSURFACE_POWER, //!< float, subsurface shading model only + SUBSURFACE_COLOR, //!< float3, subsurface and cloth shading models only + SHEEN_COLOR, //!< float3, lit shading models only, except subsurface + SHEEN_ROUGHNESS, //!< float3, lit shading models only, except subsurface and cloth + SPECULAR_COLOR, //!< float3, specular-glossiness shading model only + GLOSSINESS, //!< float, specular-glossiness shading model only + EMISSIVE, //!< float4, all shading models + NORMAL, //!< float3, all shading models only, except unlit + POST_LIGHTING_COLOR, //!< float4, all shading models + CLIP_SPACE_TRANSFORM, //!< mat4, vertex shader only + ABSORPTION, //!< float3, how much light is absorbed by the material + TRANSMISSION, //!< float, how much light is refracted through the material + IOR, //!< float, material's index of refraction + MICRO_THICKNESS, //!< float, thickness of the thin layer + BENT_NORMAL, //!< float3, all shading models only, except unlit + + // when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT +}; + +using UserVariantFilterMask = uint32_t; + +enum class UserVariantFilterBit : UserVariantFilterMask { + DIRECTIONAL_LIGHTING = 0x01, //!< Directional lighting + DYNAMIC_LIGHTING = 0x02, //!< Dynamic lighting + SHADOW_RECEIVER = 0x04, //!< Shadow receiver + SKINNING = 0x08, //!< Skinning + FOG = 0x10, //!< Fog + VSM = 0x20, //!< Variance shadow maps + SSR = 0x40, //!< Screen-space reflections + STE = 0x80, //!< Instanced stereo rendering + ALL = 0xFF, +}; + +} // namespace filament + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif diff --git a/package/android/libs/filament/include/filament/MaterialInstance.h b/package/android/libs/filament/include/filament/MaterialInstance.h new file mode 100644 index 00000000..a0edd135 --- /dev/null +++ b/package/android/libs/filament/include/filament/MaterialInstance.h @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_MATERIALINSTANCE_H +#define TNT_FILAMENT_MATERIALINSTANCE_H + +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +namespace filament { + +class Material; +class Texture; +class TextureSampler; +class UniformBuffer; +class BufferInterfaceBlock; + +class UTILS_PUBLIC MaterialInstance : public FilamentAPI { + template + using StringLiteralHelper = const char[N]; + + struct StringLiteral { + const char* UTILS_NONNULL data; + size_t size; + template + StringLiteral(StringLiteralHelper const& s) noexcept // NOLINT(google-explicit-constructor) + : data(s), size(N - 1) { + } + }; + +public: + using CullingMode = filament::backend::CullingMode; + using TransparencyMode = filament::TransparencyMode; + using DepthFunc = filament::backend::SamplerCompareFunc; + using StencilCompareFunc = filament::backend::SamplerCompareFunc; + using StencilOperation = filament::backend::StencilOperation; + using StencilFace = filament::backend::StencilFace; + + template + using is_supported_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + // these types are slower as they need a layout conversion + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type; + + /** + * Creates a new MaterialInstance using another MaterialInstance as a template for initialization. + * The new MaterialInstance is an instance of the same Material of the template instance and + * must be destroyed just like any other MaterialInstance. + * + * @param other A MaterialInstance to use as a template for initializing a new instance + * @param name A name for the new MaterialInstance or nullptr to use the template's name + * @return A new MaterialInstance + */ + static MaterialInstance* UTILS_NONNULL duplicate(MaterialInstance const* UTILS_NONNULL other, + const char* UTILS_NULLABLE name = nullptr) noexcept; + + /** + * @return the Material associated with this instance + */ + Material const* UTILS_NONNULL getMaterial() const noexcept; + + /** + * @return the name associated with this instance + */ + const char* UTILS_NONNULL getName() const noexcept; + + /** + * Set a uniform by name + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param value Value of the parameter to set. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + template> + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, T const& value); + + /** inline helper to provide the name as a null-terminated string literal */ + template> + inline void setParameter(StringLiteral name, T const& value) { + setParameter(name.data, name.size, value); + } + + /** inline helper to provide the name as a null-terminated C string */ + template> + inline void setParameter(const char* UTILS_NONNULL name, T const& value) { + setParameter(name, strlen(name), value); + } + + + /** + * Set a uniform array by name + * + * @param name Name of the parameter array as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param values Array of values to set to the named parameter array. + * @param count Size of the array to set. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + template> + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + const T* UTILS_NONNULL values, size_t count); + + /** inline helper to provide the name as a null-terminated string literal */ + template> + inline void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t count) { + setParameter(name.data, name.size, values, count); + } + + /** inline helper to provide the name as a null-terminated C string */ + template> + inline void setParameter(const char* UTILS_NONNULL name, + const T* UTILS_NONNULL values, size_t count) { + setParameter(name, strlen(name), values, count); + } + + + /** + * Set a texture as the named parameter + * + * Note: Depth textures can't be sampled with a linear filter unless the comparison mode is set + * to COMPARE_TO_TEXTURE. + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param texture Non nullptr Texture object pointer. + * @param sampler Sampler parameters. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) { + setParameter(name.data, name.size, texture, sampler); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) { + setParameter(name, strlen(name), texture, sampler); + } + + + /** + * Set an RGB color as the named parameter. + * A conversion might occur depending on the specified type + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param type Whether the color value is encoded as Linear or sRGB. + * @param color Array of read, green, blue channels values. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + RgbType type, math::float3 color); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, RgbType type, math::float3 color) { + setParameter(name.data, name.size, type, color); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) { + setParameter(name, strlen(name), type, color); + } + + + /** + * Set an RGBA color as the named parameter. + * A conversion might occur depending on the specified type + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param type Whether the color value is encoded as Linear or sRGB/A. + * @param color Array of read, green, blue and alpha channels values. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + RgbaType type, math::float4 color); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, RgbaType type, math::float4 color) { + setParameter(name.data, name.size, type, color); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) { + setParameter(name, strlen(name), type, color); + } + + /** + * Set-up a custom scissor rectangle; by default it is disabled. + * + * The scissor rectangle gets clipped by the View's viewport, in other words, the scissor + * cannot affect fragments outside of the View's Viewport. + * + * Currently the scissor is not compatible with dynamic resolution and should always be + * disabled when dynamic resolution is used. + * + * @param left left coordinate of the scissor box relative to the viewport + * @param bottom bottom coordinate of the scissor box relative to the viewport + * @param width width of the scissor box + * @param height height of the scissor box + * + * @see unsetScissor + * @see View::setViewport + * @see View::setDynamicResolutionOptions + */ + void setScissor(uint32_t left, uint32_t bottom, uint32_t width, uint32_t height) noexcept; + + /** + * Returns the scissor rectangle to its default disabled setting. + * + * Currently the scissor is not compatible with dynamic resolution and should always be + * disabled when dynamic resolution is used. + * + * @see View::setDynamicResolutionOptions + */ + void unsetScissor() noexcept; + + /** + * Sets a polygon offset that will be applied to all renderables drawn with this material + * instance. + * + * The value of the offset is scale * dz + r * constant, where dz is the change in depth + * relative to the screen area of the triangle, and r is the smallest value that is guaranteed + * to produce a resolvable offset for a given implementation. This offset is added before the + * depth test. + * + * @warning using a polygon offset other than zero has a significant negative performance + * impact, as most implementations have to disable early depth culling. DO NOT USE unless + * absolutely necessary. + * + * @param scale scale factor used to create a variable depth offset for each triangle + * @param constant scale factor used to create a constant depth offset for each triangle + */ + void setPolygonOffset(float scale, float constant) noexcept; + + /** + * Overrides the minimum alpha value a fragment must have to not be discarded when the blend + * mode is MASKED. Defaults to 0.4 if it has not been set in the parent Material. The specified + * value should be between 0 and 1 and will be clamped if necessary. + */ + void setMaskThreshold(float threshold) noexcept; + + /** + * Gets the minimum alpha value a fragment must have to not be discarded when the blend + * mode is MASKED + */ + float getMaskThreshold() const noexcept; + + /** + * Sets the screen space variance of the filter kernel used when applying specular + * anti-aliasing. The default value is set to 0.15. The specified value should be between + * 0 and 1 and will be clamped if necessary. + */ + void setSpecularAntiAliasingVariance(float variance) noexcept; + + /** + * Gets the screen space variance of the filter kernel used when applying specular + * anti-aliasing. + */ + float getSpecularAntiAliasingVariance() const noexcept; + + /** + * Sets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. The default value is set to 0.2. The specified value should be between 0 + * and 1 and will be clamped if necessary. + */ + void setSpecularAntiAliasingThreshold(float threshold) noexcept; + + /** + * Gets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. + */ + float getSpecularAntiAliasingThreshold() const noexcept; + + /** + * Enables or disables double-sided lighting if the parent Material has double-sided capability, + * otherwise prints a warning. If double-sided lighting is enabled, backface culling is + * automatically disabled. + */ + void setDoubleSided(bool doubleSided) noexcept; + + /** + * Returns whether double-sided lighting is enabled when the parent Material has double-sided + * capability. + */ + bool isDoubleSided() const noexcept; + + /** + * Specifies how transparent objects should be rendered (default is DEFAULT). + */ + void setTransparencyMode(TransparencyMode mode) noexcept; + + /** + * Returns the transparency mode. + */ + TransparencyMode getTransparencyMode() const noexcept; + + /** + * Overrides the default triangle culling state that was set on the material. + */ + void setCullingMode(CullingMode culling) noexcept; + + /** + * Returns the face culling mode. + */ + CullingMode getCullingMode() const noexcept; + + /** + * Overrides the default color-buffer write state that was set on the material. + */ + void setColorWrite(bool enable) noexcept; + + /** + * Returns whether color write is enabled. + */ + bool isColorWriteEnabled() const noexcept; + + /** + * Overrides the default depth-buffer write state that was set on the material. + */ + void setDepthWrite(bool enable) noexcept; + + /** + * Returns whether depth write is enabled. + */ + bool isDepthWriteEnabled() const noexcept; + + /** + * Overrides the default depth testing state that was set on the material. + */ + void setDepthCulling(bool enable) noexcept; + + /** + * Overrides the default depth function state that was set on the material. + */ + void setDepthFunc(DepthFunc depthFunc) noexcept; + + /** + * Returns the depth function state. + */ + DepthFunc getDepthFunc() const noexcept; + + /** + * Returns whether depth culling is enabled. + */ + bool isDepthCullingEnabled() const noexcept; + + /** + * Overrides the default stencil-buffer write state that was set on the material. + */ + void setStencilWrite(bool enable) noexcept; + + /** + * Returns whether stencil write is enabled. + */ + bool isStencilWriteEnabled() const noexcept; + + /** + * Sets the stencil comparison function (default is StencilCompareFunc::A). + * + * It's possible to set separate stencil comparison functions; one for front-facing polygons, + * and one for back-facing polygons. The face parameter determines the comparison function(s) + * updated by this call. + */ + void setStencilCompareFunction(StencilCompareFunc func, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil fail operation (default is StencilOperation::KEEP). + * + * The stencil fail operation is performed to update values in the stencil buffer when the + * stencil test fails. + * + * It's possible to set separate stencil fail operations; one for front-facing polygons, and one + * for back-facing polygons. The face parameter determines the stencil fail operation(s) updated + * by this call. + */ + void setStencilOpStencilFail(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the depth fail operation (default is StencilOperation::KEEP). + * + * The depth fail operation is performed to update values in the stencil buffer when the depth + * test fails. + * + * It's possible to set separate depth fail operations; one for front-facing polygons, and one + * for back-facing polygons. The face parameter determines the depth fail operation(s) updated + * by this call. + */ + void setStencilOpDepthFail(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the depth-stencil pass operation (default is StencilOperation::KEEP). + * + * The depth-stencil pass operation is performed to update values in the stencil buffer when + * both the stencil test and depth test pass. + * + * It's possible to set separate depth-stencil pass operations; one for front-facing polygons, + * and one for back-facing polygons. The face parameter determines the depth-stencil pass + * operation(s) updated by this call. + */ + void setStencilOpDepthStencilPass(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil reference value (default is 0). + * + * The stencil reference value is the left-hand side for stencil comparison tests. It's also + * used as the replacement stencil value when StencilOperation is REPLACE. + * + * It's possible to set separate stencil reference values; one for front-facing polygons, and + * one for back-facing polygons. The face parameter determines the reference value(s) updated by + * this call. + */ + void setStencilReferenceValue(uint8_t value, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil read mask (default is 0xFF). + * + * The stencil read mask masks the bits of the values participating in the stencil comparison + * test- both the value read from the stencil buffer and the reference value. + * + * It's possible to set separate stencil read masks; one for front-facing polygons, and one for + * back-facing polygons. The face parameter determines the stencil read mask(s) updated by this + * call. + */ + void setStencilReadMask(uint8_t readMask, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil write mask (default is 0xFF). + * + * The stencil write mask masks the bits in the stencil buffer updated by stencil operations. + * + * It's possible to set separate stencil write masks; one for front-facing polygons, and one for + * back-facing polygons. The face parameter determines the stencil write mask(s) updated by this + * call. + */ + void setStencilWriteMask(uint8_t writeMask, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + +protected: + // prevent heap allocation + ~MaterialInstance() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_MATERIALINSTANCE_H diff --git a/package/android/libs/filament/include/filament/MorphTargetBuffer.h b/package/android/libs/filament/include/filament/MorphTargetBuffer.h new file mode 100644 index 00000000..655bb8d8 --- /dev/null +++ b/package/android/libs/filament/include/filament/MorphTargetBuffer.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_MORPHTARGETBUFFER_H +#define TNT_FILAMENT_MORPHTARGETBUFFER_H + +#include + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * MorphTargetBuffer is used to hold morphing data (positions and tangents). + * + * Both positions and tangents are required. + * + */ +class UTILS_PUBLIC MorphTargetBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the morph targets in vertex counts. + * @param vertexCount Number of vertex counts the morph targets can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + /** + * Size of the morph targets in targets. + * @param count Number of targets the morph targets can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& count(size_t count) noexcept; + + /** + * Creates the MorphTargetBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this MorphTargetBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + MorphTargetBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FMorphTargetBuffer; + }; + + /** + * 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 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* UTILS_NONNULL positions, size_t count, size_t offset = 0); + + /** + * 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 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* UTILS_NONNULL positions, size_t count, size_t offset = 0); + + /** + * 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 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 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* UTILS_NONNULL tangents, size_t count, size_t offset = 0); + + /** + * Returns the vertex count of this MorphTargetBuffer. + * @return The number of vertices the MorphTargetBuffer holds. + */ + size_t getVertexCount() const noexcept; + + /** + * Returns the target count of this MorphTargetBuffer. + * @return The number of targets the MorphTargetBuffer holds. + */ + size_t getCount() const noexcept; + +protected: + // prevent heap allocation + ~MorphTargetBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_MORPHTARGETBUFFER_H diff --git a/package/android/libs/filament/include/filament/Options.h b/package/android/libs/filament/include/filament/Options.h new file mode 100644 index 00000000..3966053e --- /dev/null +++ b/package/android/libs/filament/include/filament/Options.h @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_OPTIONS_H +#define TNT_FILAMENT_OPTIONS_H + +#include + +#include +#include + +#include + +#include + +namespace filament { + +class Texture; + +/** + * Generic quality level. + */ +enum class QualityLevel : uint8_t { + LOW, + MEDIUM, + HIGH, + ULTRA +}; + +enum class BlendMode : uint8_t { + OPAQUE, + TRANSLUCENT +}; + +/** + * Dynamic resolution can be used to either reach a desired target frame rate + * by lowering the resolution of a View, or to increase the quality when the + * rendering is faster than the target frame rate. + * + * This structure can be used to specify the minimum scale factor used when + * lowering the resolution of a View, and the maximum scale factor used when + * increasing the resolution for higher quality rendering. The scale factors + * can be controlled on each X and Y axis independently. By default, all scale + * factors are set to 1.0. + * + * enabled: enable or disables dynamic resolution on a View + * + * homogeneousScaling: by default the system scales the major axis first. Set this to true + * to force homogeneous scaling. + * + * minScale: the minimum scale in X and Y this View should use + * + * maxScale: the maximum scale in X and Y this View should use + * + * quality: upscaling quality. + * LOW: 1 bilinear tap, Medium: 4 bilinear taps, High: 9 bilinear taps (tent) + * + * \note + * Dynamic resolution is only supported on platforms where the time to render + * a frame can be measured accurately. Dynamic resolution is currently only + * supported on Android. + * + * @see Renderer::FrameRateOptions + * + */ +struct DynamicResolutionOptions { + math::float2 minScale = {0.5f, 0.5f}; //!< minimum scale factors in x and y %codegen_java_float% + math::float2 maxScale = {1.0f, 1.0f}; //!< maximum scale factors in x and y %codegen_java_float% + float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)] + bool enabled = false; //!< enable or disable dynamic resolution + bool homogeneousScaling = false; //!< set to true to force homogeneous scaling + + /** + * 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. + */ + QualityLevel quality = QualityLevel::LOW; +}; + +/** + * Options to control the bloom effect + * + * enabled: Enable or disable the bloom post-processing effect. Disabled by default. + * + * levels: Number of successive blurs to achieve the blur effect, the minimum is 3 and the + * maximum is 12. This value together with resolution influences the spread of the + * blur effect. This value can be silently reduced to accommodate the original + * image size. + * + * resolution: Resolution of bloom's minor axis. The minimum value is 2^levels and the + * the maximum is lower of the original resolution and 4096. This parameter is + * silently clamped to the minimum and maximum. + * It is highly recommended that this value be smaller than the target resolution + * after dynamic resolution is applied (horizontally and vertically). + * + * strength: how much of the bloom is added to the original image. Between 0 and 1. + * + * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original + * image (true). + * + * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons and is usually needed when a dirt texture is used. + * + * dirt: A dirt/scratch/smudges texture (that can be RGB), which gets added to the + * bloom effect. Smudges are visible where bloom occurs. Threshold must be + * enabled for the dirt effect to work properly. + * + * dirtStrength: Strength of the dirt texture. + */ +struct BloomOptions { + enum class BlendMode : uint8_t { + ADD, //!< Bloom is modulated by the strength parameter and added to the scene + INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter + }; + Texture* dirt = nullptr; //!< user provided dirt texture %codegen_skip_json% %codegen_skip_javascript% + float dirtStrength = 0.2f; //!< strength of the dirt texture %codegen_skip_json% %codegen_skip_javascript% + float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0 + uint32_t resolution = 384; //!< resolution of vertical axis (2^levels to 2048) + uint8_t levels = 6; //!< number of blur levels (1 to 11) + BlendMode blendMode = BlendMode::ADD; //!< how the bloom effect is applied + bool threshold = true; //!< whether to threshold the source + bool enabled = false; //!< enable or disable bloom + float highlight = 1000.0f; //!< limit highlights to this value before bloom [10, +inf] + + /** + * Bloom quality level. + * LOW (default): use a more optimized down-sampling filter, however there can be artifacts + * with dynamic resolution, this can be alleviated by using the homogenous mode. + * MEDIUM: Good balance between quality and performance. + * HIGH: In this mode the bloom resolution is automatically increased to avoid artifacts. + * This mode can be significantly slower on mobile, especially at high resolution. + * This mode greatly improves the anamorphic bloom. + */ + QualityLevel quality = QualityLevel::LOW; + + bool lensFlare = false; //!< enable screen-space lens flare + bool starburst = true; //!< enable starburst effect on lens flare + float chromaticAberration = 0.005f; //!< amount of chromatic aberration + uint8_t ghostCount = 4; //!< number of flare "ghosts" + float ghostSpacing = 0.6f; //!< spacing of the ghost in screen units [0, 1[ + float ghostThreshold = 10.0f; //!< hdr threshold for the ghosts + float haloThickness = 0.1f; //!< thickness of halo in vertical screen units, 0 to disable + float haloRadius = 0.4f; //!< radius of halo in vertical screen units [0, 0.5] + float haloThreshold = 10.0f; //!< hdr threshold for the halo +}; + +/** + * Options to control large-scale fog in the scene + */ +struct FogOptions { + /** + * Distance in world units [m] from the camera to where the fog starts ( >= 0.0 ) + */ + float distance = 0.0f; + + /** + * Distance in world units [m] after which the fog calculation is disabled. + * This can be used to exclude the skybox, which is desirable if it already contains clouds or + * fog. The default value is +infinity which applies the fog to everything. + * + * Note: The SkyBox is typically at a distance of 1e19 in world space (depending on the near + * plane distance and projection used though). + */ + float cutOffDistance = INFINITY; + + /** + * fog's maximum opacity between 0 and 1 + */ + float maximumOpacity = 1.0f; + + /** + * Fog's floor in world units [m]. This sets the "sea level". + */ + float height = 0.0f; + + /** + * How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m]. + * It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a + * factor 2.78 (e) change in fog density. + * + * A falloff of 0 means the fog density is constant everywhere and may result is slightly + * faster computations. + */ + float heightFalloff = 1.0f; + + /** + * Fog's color is used for ambient light in-scattering, a good value is + * to use the average of the ambient light, possibly tinted towards blue + * for outdoors environments. Color component's values should be between 0 and 1, values + * above one are allowed but could create a non energy-conservative fog (this is dependant + * on the IBL's intensity as well). + * + * We assume that our fog has no absorption and therefore all the light it scatters out + * becomes ambient light in-scattering and has lost all directionality, i.e.: scattering is + * isotropic. This somewhat simulates Rayleigh scattering. + * + * This value is used as a tint instead, when fogColorFromIbl is enabled. + * + * @see fogColorFromIbl + */ + LinearColor color = { 1.0f, 1.0f, 1.0f }; + + /** + * Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much + * light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces + * the incoming light to 37% of its original value. + * + * Note: The extinction factor is related to the fog density, it's usually some constant K times + * the density at sea level (more specifically at fog height). The constant K depends on + * the composition of the fog/atmosphere. + * + * For historical reason this parameter is called `density`. + */ + float density = 0.1f; + + /** + * Distance in world units [m] from the camera where the Sun in-scattering starts. + */ + float inScatteringStart = 0.0f; + + /** + * Very inaccurately simulates the Sun's in-scattering. That is, the light from the sun that + * is scattered (by the fog) towards the camera. + * Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100). + * Smaller values result is a larger scattering size. + */ + float inScatteringSize = -1.0f; + + /** + * The fog color will be sampled from the IBL in the view direction and tinted by `color`. + * Depending on the scene this can produce very convincing results. + * + * This simulates a more anisotropic phase-function. + * + * `fogColorFromIbl` is ignored when skyTexture is specified. + * + * @see skyColor + */ + bool fogColorFromIbl = false; + + /** + * skyTexture must be a mipmapped cubemap. When provided, the fog color will be sampled from + * this texture, higher resolution mip levels will be used for objects at the far clip plane, + * and lower resolution mip levels for objects closer to the camera. The skyTexture should + * typically be heavily blurred; a typical way to produce this texture is to blur the base + * level with a strong gaussian filter or even an irradiance filter and then generate mip + * levels as usual. How blurred the base level is somewhat of an artistic decision. + * + * This simulates a more anisotropic phase-function. + * + * `fogColorFromIbl` is ignored when skyTexture is specified. + * + * @see Texture + * @see fogColorFromIbl + */ + Texture* skyColor = nullptr; //!< %codegen_skip_json% %codegen_skip_javascript% + + /** + * Enable or disable large-scale fog + */ + bool enabled = false; +}; + +/** + * Options to control Depth of Field (DoF) effect in the scene. + * + * cocScale can be used to set the depth of field blur independently from the camera + * aperture, e.g. for artistic reasons. This can be achieved by setting: + * cocScale = cameraAperture / desiredDoFAperture + * + * @see Camera + */ +struct DepthOfFieldOptions { + enum class Filter : uint8_t { + NONE, + UNUSED, + MEDIAN + }; + float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur) + float cocAspectRatio = 1.0f; //!< width/height aspect ratio of the circle of confusion (simulate anamorphic lenses) + float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation) + bool enabled = false; //!< enable or disable depth of field effect + Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel + bool nativeResolution = false; //!< perform DoF processing at native resolution + /** + * 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. + * + * @{ + */ + uint8_t foregroundRingCount = 0; //!< number of kernel rings for foreground tiles + uint8_t backgroundRingCount = 0; //!< number of kernel rings for background tiles + uint8_t fastGatherRingCount = 0; //!< number of kernel rings for fast tiles + /** @}*/ + + /** + * 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. + */ + uint16_t maxForegroundCOC = 0; + + /** + * 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. + */ + uint16_t maxBackgroundCOC = 0; +}; + +/** + * Options to control the vignetting effect. + */ +struct VignetteOptions { + float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1 + float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0) + float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1 + LinearColorA color = {0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored + bool enabled = false; //!< enables or disables the vignette effect +}; + +/** + * Structure used to set the precision of the color buffer and related quality settings. + * + * @see setRenderQuality, getRenderQuality + */ +struct 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). + */ + QualityLevel hdrColorBuffer = QualityLevel::HIGH; +}; + +/** + * Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT) + * @see setAmbientOcclusionOptions() + */ +struct AmbientOcclusionOptions { + float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10. + float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive. + float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm. + float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0. + float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect. + float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering + QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO. + QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness + QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality + bool enabled = false; //!< enables or disables screen-space ambient occlusion + bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO + float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider + /** + * Screen Space Cone Tracing (SSCT) options + * 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 + 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 ssct; // %codegen_skip_javascript% %codegen_java_flatten% +}; + +/** + * Options for Multi-Sample Anti-aliasing (MSAA) + * @see setMultiSampleAntiAliasingOptions() + */ +struct MultiSampleAntiAliasingOptions { + bool enabled = false; //!< enables or disables msaa + + /** + * 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. + */ + uint8_t sampleCount = 4; + + /** + * custom resolve improves quality for HDR scenes, but may impact performance. + */ + bool customResolve = false; +}; + +/** + * Options for Temporal Anti-aliasing (TAA) + * Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process + * shaders to be recompiled. These options should be changed or set during initialization. + * `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time. + * + * `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state. + * see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information. + * + * @see setTemporalAntiAliasingOptions() + */ +struct TemporalAntiAliasingOptions { + float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother) + float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA). + float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2) + float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true. + bool enabled = false; //!< enables or disables temporal anti-aliasing + bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA] + + enum class BoxType : uint8_t { + AABB, //!< use an AABB neighborhood + VARIANCE, //!< use the variance of the neighborhood (not recommended) + AABB_VARIANCE //!< use both AABB and variance + }; + + enum class BoxClipping : uint8_t { + ACCURATE, //!< Accurate box clipping + CLAMP, //!< clamping + NONE //!< no rejections (use for debugging) + }; + + enum class JitterPattern : uint8_t { + RGSS_X4, //! 4-samples, rotated grid sampling + UNIFORM_HELIX_X4, //! 4-samples, uniform grid in helix sequence + HALTON_23_X8, //! 8-samples of halton 2,3 + HALTON_23_X16, //! 16-samples of halton 2,3 + HALTON_23_X32 //! 32-samples of halton 2,3 + }; + + bool filterHistory = true; //!< whether to filter the history buffer + bool filterInput = true; //!< whether to apply the reconstruction filter to the input + bool useYCoCg = false; //!< whether to use the YcoCg color-space for history rejection + BoxType boxType = BoxType::AABB; //!< type of color gamut box + BoxClipping boxClipping = BoxClipping::ACCURATE; //!< clipping algorithm + JitterPattern jitterPattern = JitterPattern::HALTON_23_X16; //! Jitter Pattern + float varianceGamma = 1.0f; //! High values increases ghosting artefact, lower values increases jittering, range [0.75, 1.25] + + bool preventFlickering = false; //!< adjust the feedback dynamically to reduce flickering + bool historyReprojection = true; //!< whether to apply history reprojection (debug option) +}; + +/** + * Options for Screen-space Reflections. + * @see setScreenSpaceReflectionsOptions() + */ +struct ScreenSpaceReflectionsOptions { + float thickness = 0.1f; //!< ray thickness, in world units + float bias = 0.01f; //!< bias, in world units, to prevent self-intersections + float maxDistance = 3.0f; //!< maximum distance, in world units, to raycast + float stride = 2.0f; //!< stride, in texels, for samples along the ray. + bool enabled = false; +}; + +/** + * Options for the screen-space guard band. + * A guard band can be enabled to avoid some artifacts towards the edge of the screen when + * using screen-space effects such as SSAO. Enabling the guard band reduces performance slightly. + * Currently the guard band can only be enabled or disabled. + */ +struct GuardBandOptions { + bool enabled = false; +}; + +/** + * List of available post-processing anti-aliasing techniques. + * @see setAntiAliasing, getAntiAliasing, setSampleCount + */ +enum class AntiAliasing : uint8_t { + NONE, //!< no anti aliasing performed as part of post-processing + FXAA //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default). +}; + +/** + * List of available post-processing dithering techniques. + */ +enum class Dithering : uint8_t { + NONE, //!< No dithering + TEMPORAL //!< Temporal dithering (default) +}; + +/** + * List of available shadow mapping techniques. + * @see setShadowType + */ +enum class ShadowType : uint8_t { + PCF, //!< percentage-closer filtered shadows (default) + VSM, //!< variance shadows + DPCF, //!< PCF with contact hardening simulation + PCSS, //!< PCF with soft shadows and contact hardening + PCFd, // for debugging only, don't use. +}; + +/** + * View-level options for VSM Shadowing. + * @see setVsmShadowOptions() + * @warning This API is still experimental and subject to change. + */ +struct 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. + */ + uint8_t anisotropy = 0; + + /** + * Whether to generate mipmaps for all VSM shadow maps. + */ + bool mipmapping = false; + + /** + * The number of MSAA samples to use when rendering VSM shadow maps. + * Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns + * off MSAA. + * Higher values may not be available depending on the underlying hardware. + */ + uint8_t msaaSamples = 1; + + /** + * Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits + * precision is rarely needed, but it does reduces light leaks as well as "fading" + * of the shadows in some situations. Setting highPrecision to true for a single + * shadow map will double the memory usage of all shadow maps. + */ + bool highPrecision = false; + + /** + * VSM minimum variance scale, must be positive. + */ + float minVarianceScale = 0.5f; + + /** + * VSM light bleeding reduction amount, between 0 and 1. + */ + float lightBleedReduction = 0.15f; +}; + +/** + * View-level options for DPCF and PCSS Shadowing. + * @see setSoftShadowOptions() + * @warning This API is still experimental and subject to change. + */ +struct SoftShadowOptions { + /** + * Globally scales the penumbra of all DPCF and PCSS shadows + * Acceptable values are greater than 0 + */ + float penumbraScale = 1.0f; + + /** + * 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. + */ + float penumbraRatioScale = 1.0f; +}; + +/** + * Options for stereoscopic (multi-eye) rendering. + */ +struct StereoscopicOptions { + bool enabled = false; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_OPTIONS_H diff --git a/package/android/libs/filament/include/filament/RenderTarget.h b/package/android/libs/filament/include/filament/RenderTarget.h new file mode 100644 index 00000000..fc76111d --- /dev/null +++ b/package/android/libs/filament/include/filament/RenderTarget.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2019 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_RENDERTARGET_H +#define TNT_FILAMENT_RENDERTARGET_H + +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FRenderTarget; + +class Engine; +class Texture; + +/** + * An offscreen render target that can be associated with a View and contains + * weak references to a set of attached Texture objects. + * + * RenderTarget is intended to be used with the View's post-processing disabled for the most part. + * especially when a DEPTH attachment is also used (see Builder::texture()). + * + * Custom RenderTarget are ultimately intended to render into textures that might be used during + * the main render pass. + * + * Clients are responsible for the lifetime of all associated Texture attachments. + * + * @see View + */ +class UTILS_PUBLIC RenderTarget : public FilamentAPI { + struct BuilderDetails; + +public: + using CubemapFace = backend::TextureCubemapFace; + + /** Minimum number of color attachment supported */ + static constexpr uint8_t MIN_SUPPORTED_COLOR_ATTACHMENTS_COUNT = + backend::MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; + + /** Maximum number of color attachment supported */ + static constexpr uint8_t MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT = + backend::MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; + + /** + * Attachment identifiers + */ + enum class AttachmentPoint : uint8_t { + COLOR0 = 0, //!< identifies the 1st color attachment + COLOR1 = 1, //!< identifies the 2nd color attachment + COLOR2 = 2, //!< identifies the 3rd color attachment + COLOR3 = 3, //!< identifies the 4th color attachment + COLOR4 = 4, //!< identifies the 5th color attachment + COLOR5 = 5, //!< identifies the 6th color attachment + COLOR6 = 6, //!< identifies the 7th color attachment + COLOR7 = 7, //!< identifies the 8th color attachment + DEPTH = MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT, //!< identifies the depth attachment + COLOR = COLOR0, //!< identifies the 1st color attachment + }; + + //! Use Builder to construct a RenderTarget object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Sets a texture to a given attachment point. + * + * When using a DEPTH attachment, it is important to always disable post-processing + * in the View. Failing to do so will cause the DEPTH attachment to be ignored in most + * cases. + * + * When the intention is to keep the content of the DEPTH attachment after rendering, + * Usage::SAMPLEABLE must be set on the DEPTH attachment, otherwise the content of the + * DEPTH buffer may be discarded. + * + * @param attachment The attachment point of the texture. + * @param texture The associated texture object. + * @return A reference to this Builder for chaining calls. + */ + Builder& texture(AttachmentPoint attachment, Texture* UTILS_NULLABLE texture) noexcept; + + /** + * Sets the mipmap level for a given attachment point. + * + * @param attachment The attachment point of the texture. + * @param level The associated mipmap level, 0 by default. + * @return A reference to this Builder for chaining calls. + */ + Builder& mipLevel(AttachmentPoint attachment, uint8_t level) noexcept; + + /** + * Sets the cubemap face for a given attachment point. + * + * @param attachment The attachment point. + * @param face The associated cubemap face. + * @return A reference to this Builder for chaining calls. + */ + Builder& face(AttachmentPoint attachment, CubemapFace face) noexcept; + + /** + * Sets the layer for a given attachment point (for 3D textures). + * + * @param attachment The attachment point. + * @param layer The associated cubemap layer. + * @return A reference to this Builder for chaining calls. + */ + Builder& layer(AttachmentPoint attachment, uint32_t layer) noexcept; + + /** + * Creates the RenderTarget object and returns a pointer to it. + * + * @return pointer to the newly created object. + */ + RenderTarget* UTILS_NONNULL build(Engine& engine); + + private: + friend class FRenderTarget; + }; + + /** + * Gets the texture set on the given attachment point + * @param attachment Attachment point + * @return A Texture object or nullptr if no texture is set for this attachment point + */ + Texture* UTILS_NULLABLE getTexture(AttachmentPoint attachment) const noexcept; + + /** + * Returns the mipmap level set on the given attachment point + * @param attachment Attachment point + * @return the mipmap level set on the given attachment point + */ + uint8_t getMipLevel(AttachmentPoint attachment) const noexcept; + + /** + * Returns the face of a cubemap set on the given attachment point + * @param attachment Attachment point + * @return A cubemap face identifier. This is only relevant if the attachment's texture is + * a cubemap. + */ + CubemapFace getFace(AttachmentPoint attachment) const noexcept; + + /** + * Returns the texture-layer set on the given attachment point + * @param attachment Attachment point + * @return A texture layer. This is only relevant if the attachment's texture is a 3D texture. + */ + uint32_t getLayer(AttachmentPoint attachment) const noexcept; + + /** + * Returns the number of color attachments usable by this instance of Engine. This method is + * guaranteed to return at least MIN_SUPPORTED_COLOR_ATTACHMENTS_COUNT and at most + * MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT. + * @return Number of color attachments usable in a render target. + */ + uint8_t getSupportedColorAttachmentsCount() const noexcept; + +protected: + // prevent heap allocation + ~RenderTarget() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERTARGET_H diff --git a/package/android/libs/filament/include/filament/RenderableManager.h b/package/android/libs/filament/include/filament/RenderableManager.h new file mode 100644 index 00000000..bec39e4a --- /dev/null +++ b/package/android/libs/filament/include/filament/RenderableManager.h @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_RENDERABLEMANAGER_H +#define TNT_FILAMENT_RENDERABLEMANAGER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class BufferObject; +class Engine; +class IndexBuffer; +class MaterialInstance; +class Renderer; +class SkinningBuffer; +class VertexBuffer; +class Texture; +class InstanceBuffer; + +class FEngine; +class FRenderPrimitive; +class FRenderableManager; + +/** + * Factory and manager for \em renderables, which are entities that can be drawn. + * + * Renderables are bundles of \em primitives, each of which has its own geometry and material. All + * primitives in a particular renderable share a set of rendering attributes, such as whether they + * cast shadows or use vertex skinning. + * + * Usage example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto renderable = utils::EntityManager::get().create(); + * + * RenderableManager::Builder(1) + * .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + * .material(0, matInstance) + * .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vertBuffer, indBuffer, 0, 3) + * .receiveShadows(false) + * .build(engine, renderable); + * + * scene->addEntity(renderable); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To modify the state of an existing renderable, clients should first use RenderableManager + * to get a temporary handle called an \em instance. The instance can then be used to get or set + * the renderable's state. Please note that instances are ephemeral; clients should store entities, + * not instances. + * + * - For details about constructing renderables, see RenderableManager::Builder. + * - To associate a 4x4 transform with an entity, see TransformManager. + * - To associate a human-readable label with an entity, see utils::NameComponentManager. + */ +class UTILS_PUBLIC RenderableManager : public FilamentAPI { + struct BuilderDetails; + +public: + using Instance = utils::EntityInstance; + using PrimitiveType = backend::PrimitiveType; + + /** + * Checks if the given entity already has a renderable component. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * Gets a temporary handle that can be used to access the renderable state. + * + * @return Non-zero handle if the entity has a renderable component, 0 otherwise. + */ + Instance getInstance(utils::Entity e) const noexcept; + + /** + * @return the number of Components + */ + size_t getComponentCount() const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * The transformation associated with a skinning joint. + * + * Clients can specify bones either using this quat-vec3 pair, or by using 4x4 matrices. + */ + struct Bone { + math::quatf unitQuaternion = { 1.f, 0.f, 0.f, 0.f }; + math::float3 translation = { 0.f, 0.f, 0.f }; + float reserved = 0; + }; + + /** + * Adds renderable components to entities using a builder pattern. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + enum Result { Error = -1, Success = 0 }; + + /** + * Default render channel + * @see Builder::channel() + */ + static constexpr uint8_t DEFAULT_CHANNEL = 2u; + + /** + * Creates a builder for renderable components. + * + * @param count the number of primitives that will be supplied to the builder + * + * Note that builders typically do not have a long lifetime since clients should discard + * them after calling build(). For a usage example, see RenderableManager. + */ + explicit Builder(size_t count) noexcept; + + /*! \cond PRIVATE */ + Builder(Builder const& rhs) = delete; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder& rhs) = delete; + Builder& operator=(Builder&& rhs) noexcept; + /*! \endcond */ + + /** + * Specifies the geometry data for a primitive. + * + * Filament primitives must have an associated VertexBuffer and IndexBuffer. Typically, each + * primitive is specified with a pair of daisy-chained calls: \c geometry(...) and \c + * material(...). + * + * @param index zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param type specifies the topology of the primitive (e.g., \c RenderableManager::PrimitiveType::TRIANGLES) + * @param vertices specifies the vertex buffer, which in turn specifies a set of attributes + * @param indices specifies the index buffer (either u16 or u32) + * @param offset specifies where in the index buffer to start reading (expressed as a number of indices) + * @param minIndex specifies the minimum index contained in the index buffer + * @param maxIndex specifies the maximum index contained in the index buffer + * @param count number of indices to read (for triangles, this should be a multiple of 3) + */ + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t minIndex, size_t maxIndex, size_t count) noexcept; + + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t count) noexcept; //!< \overload + + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices) noexcept; //!< \overload + + /** + * Binds a material instance to the specified primitive. + * + * If no material is specified for a given primitive, Filament will fall back to a basic + * default material. + * + * The MaterialInstance's material must have a feature level equal or lower to the engine's + * selected feature level. + * + * @param index zero-based index of the primitive, must be less than the count passed to + * Builder constructor + * @param materialInstance the material to bind + * + * @see Engine::setActiveFeatureLevel + */ + Builder& material(size_t index, + MaterialInstance const* UTILS_NONNULL materialInstance) noexcept; + + /** + * The axis-aligned bounding box of the renderable. + * + * This is an object-space AABB used for frustum culling. For skinning and morphing, this + * should encompass all possible vertex positions. It is mandatory unless culling is + * disabled for the renderable. + * + * \see computeAABB() + */ + Builder& boundingBox(const Box& axisAlignedBoundingBox) noexcept; + + /** + * Sets bits in a visibility mask. By default, this is 0x1. + * + * This feature provides a simple mechanism for hiding and showing groups of renderables + * in a Scene. See View::setVisibleLayers(). + * + * For example, to set bit 1 and reset bits 0 and 2 while leaving all other bits unaffected, + * do: `builder.layerMask(7, 2)`. + * + * To change this at run time, see RenderableManager::setLayerMask. + * + * @param select the set of bits to affect + * @param values the replacement values for the affected bits + */ + Builder& layerMask(uint8_t select, uint8_t values) noexcept; + + /** + * Provides coarse-grained control over draw order. + * + * In general Filament reserves the right to re-order renderables to allow for efficient + * rendering. However clients can control ordering at a coarse level using \em priority. + * The priority is applied separately for opaque and translucent objects, that is, opaque + * objects are always drawn before translucent objects regardless of the priority. + * + * For example, this could be used to draw a semitransparent HUD on top of everything, + * without using a separate View. Note that priority is completely orthogonal to + * Builder::layerMask, which merely controls visibility. + * + * The Skybox always using the lowest priority, so it's drawn last, which may improve + * performance. + * + * @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority + * (rendered last). + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::channel() + * @see RenderableManager::setPriority() + * @see RenderableManager::setBlendOrderAt() + */ + Builder& priority(uint8_t priority) noexcept; + + /** + * Set the channel this renderable is associated to. There can be 4 channels. + * All renderables in a given channel are rendered together, regardless of anything else. + * They are sorted as usual within a channel. + * Channels work similarly to priorities, except that they enforce the strongest ordering. + * + * Channels 0 and 1 may not have render primitives using a material with `refractionType` + * set to `screenspace`. + * + * @param channel clamped to the range [0..3], defaults to 2. + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::priority() + * @see RenderableManager::setBlendOrderAt() + */ + Builder& channel(uint8_t channel) noexcept; + + /** + * Controls frustum culling, true by default. + * + * \note Do not confuse frustum culling with backface culling. The latter is controlled via + * the material. + */ + Builder& culling(bool enable) noexcept; + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * + * @param channel Light channel to enable or disable, between 0 and 7. + * @param enable Whether to enable or disable the light channel. + */ + Builder& lightChannel(unsigned int channel, bool enable = true) noexcept; + + /** + * Controls if this renderable casts shadows, false by default. + * + * If the View's shadow type is set to ShadowType::VSM, castShadows should only be disabled + * if either is true: + * - receiveShadows is also disabled + * - the object is guaranteed to not cast shadows on itself or other objects (for example, + * a ground plane) + */ + Builder& castShadows(bool enable) noexcept; + + /** + * Controls if this renderable receives shadows, true by default. + */ + Builder& receiveShadows(bool enable) noexcept; + + /** + * Controls if this renderable uses screen-space contact shadows. This is more + * expensive but can improve the quality of shadows, especially in large scenes. + * (off by default). + */ + Builder& screenSpaceContactShadows(bool enable) noexcept; + + /** + * Allows bones to be swapped out and shared using SkinningBuffer. + * + * If skinning buffer mode is enabled, clients must call setSkinningBuffer() rather than + * setBones(). This allows sharing of data between renderables. + * + * @param enabled If true, enables buffer object mode. False by default. + */ + Builder& enableSkinningBuffers(bool enabled = true) noexcept; + + /** + * Controls if this renderable is affected by the large-scale fog. + * @param enabled If true, enables large-scale fog on this object. Disables it otherwise. + * True by default. + * @return A reference to this Builder for chaining calls. + */ + Builder& fog(bool enabled = true) noexcept; + + /** + * Enables GPU vertex skinning for up to 255 bones, 0 by default. + * + * Skinning Buffer mode must be enabled. + * + * Each vertex can be affected by up to 4 bones simultaneously. The attached + * VertexBuffer must provide data in the \c BONE_INDICES slot (uvec4) and the + * \c BONE_WEIGHTS slot (float4). + * + * See also RenderableManager::setSkinningBuffer() or SkinningBuffer::setBones(), + * which can be called on a per-frame basis to advance the animation. + * + * @param skinningBuffer nullptr to disable, otherwise the SkinningBuffer to use + * @param count 0 to disable, otherwise the number of bone transforms (up to 255) + * @param offset offset in the SkinningBuffer + */ + Builder& skinning(SkinningBuffer* UTILS_NONNULL skinningBuffer, + size_t count, size_t offset) noexcept; + + + /** + * Enables GPU vertex skinning for up to 255 bones, 0 by default. + * + * Skinning Buffer mode must be disabled. + * + * Each vertex can be affected by up to 4 bones simultaneously. The attached + * VertexBuffer must provide data in the \c BONE_INDICES slot (uvec4) and the + * \c BONE_WEIGHTS slot (float4). + * + * See also RenderableManager::setBones(), which can be called on a per-frame basis + * to advance the animation. + * + * @param boneCount 0 to disable, otherwise the number of bone transforms (up to 255) + * @param transforms the initial set of transforms (one for each bone) + */ + Builder& skinning(size_t boneCount, math::mat4f const* UTILS_NONNULL transforms) noexcept; + Builder& skinning(size_t boneCount, Bone const* UTILS_NONNULL bones) noexcept; //!< \overload + Builder& skinning(size_t boneCount) noexcept; //!< \overload + + /** + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs per vertex bonesPerVertex is not limited to 4 bones. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data must be rectangular and number of bone pairs must be same for all vertices of this + * primitive. + * The data is arranged sequentially, all bone pairs for the first vertex, then for the + * second vertex, and so on. + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeights pairs of bone index and bone weight for all vertices + * sequentially + * @param count number of all pairs, must be a multiple of vertexCount of the primitive + * count = vertexCount * bonesPerVertex + * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive + * + * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex, + math::float2 const* UTILS_NONNULL indicesAndWeights, + size_t count, size_t bonesPerVertex) noexcept; + + /** + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be + * variable. + * The vector of the vertices contains the vectors of the pairs + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices of + * the primitive sequentially + * + * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex, + utils::FixedCapacityVector< + utils::FixedCapacityVector> indicesAndWeightsVector) noexcept; + /** + * Controls if the renderable has vertex morphing targets, zero by default. This is + * required to enable GPU morphing. + * + * Filament supports two morphing modes: standard (default) and legacy. + * + * For standard morphing, A MorphTargetBuffer must be created and provided via + * RenderableManager::setMorphTargetBufferAt(). Standard morphing supports up to + * \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets. + * + * For legacy morphing, the attached VertexBuffer must provide data in the + * appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only + * supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must + * be enabled on the material definition: either via the legacyMorphing material attribute + * or by calling filamat::MaterialBuilder::useLegacyMorphing(). + * + * See also RenderableManager::setMorphWeights(), which can be called on a per-frame basis + * to advance the animation. + */ + Builder& morphing(size_t targetCount) noexcept; + + /** + * Specifies the morph target buffer for a primitive. + * + * The morph target buffer must have an associated renderable and geometry. Two conditions + * must be met: + * 1. The number of morph targets in the buffer must equal the renderable's morph target + * count. + * 2. The vertex count of each morph target must equal the geometry's vertex count. + * + * @param level the level of detail (lod), only 0 can be specified + * @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param morphTargetBuffer specifies the morph target buffer + * @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices) + * @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3) + */ + Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, + size_t offset, size_t count) noexcept; + + inline Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept; + + /** + * Sets the drawing order for blended primitives. The drawing order is either global or + * local (default) to this Renderable. In either case, the Renderable priority takes + * precedence. + * + * @param primitiveIndex the primitive of interest + * @param order draw order number (0 by default). Only the lowest 15 bits are used. + * + * @return Builder reference for chaining calls. + * + * @see globalBlendOrderEnabled + */ + Builder& blendOrder(size_t primitiveIndex, uint16_t order) noexcept; + + /** + * Sets whether the blend order is global or local to this Renderable (by default). + * + * @param primitiveIndex the primitive of interest + * @param enabled true for global, false for local blend ordering. + * + * @return Builder reference for chaining calls. + * + * @see blendOrder + */ + Builder& globalBlendOrderEnabled(size_t primitiveIndex, bool enabled) noexcept; + + /** + * Specifies the number of draw instances of this renderable. The default is 1 instance and + * the maximum number of instances allowed is 32767. 0 is invalid. + * + * All instances are culled using the same bounding box, so care must be taken to make + * sure all instances render inside the specified bounding box. + * + * The material must set its `instanced` parameter to `true` in order to use + * getInstanceIndex() in the vertex or fragment shader to get the instance index and + * possibly adjust the position or transform. + * + * @param instanceCount the number of instances silently clamped between 1 and 32767. + */ + Builder& instances(size_t instanceCount) noexcept; + + /** + * Specifies the number of draw instances of this renderable and an \c InstanceBuffer + * containing their local transforms. The default is 1 instance and the maximum number of + * instances allowed when supplying transforms is given by + * \c Engine::getMaxAutomaticInstances (64 on most platforms). 0 is invalid. The + * \c InstanceBuffer must not be destroyed before this renderable. + * + * All instances are culled using the same bounding box, so care must be taken to make + * sure all instances render inside the specified bounding box. + * + * The material must set its `instanced` parameter to `true` in order to use + * \c getInstanceIndex() in the vertex or fragment shader to get the instance index. + * + * Only the \c VERTEX_DOMAIN_OBJECT vertex domain is supported. + * + * The local transforms of each instance can be updated with + * \c InstanceBuffer::setLocalTransforms. + * + * \see InstanceBuffer + * \see instances(size_t, * math::mat4f const*) + * @param instanceCount the number of instances, silently clamped between 1 and + * the result of Engine::getMaxAutomaticInstances(). + * @param instanceBuffer an InstanceBuffer containing at least instanceCount transforms + */ + Builder& instances(size_t instanceCount, + InstanceBuffer* UTILS_NONNULL instanceBuffer) noexcept; + + /** + * Adds the Renderable component to an entity. + * + * @param engine Reference to the filament::Engine to associate this Renderable with. + * @param entity Entity to add the Renderable component to. + * @return Success if the component was created successfully, Error otherwise. + * + * If exceptions are disabled and an error occurs, this function is a no-op. + * Success can be checked by looking at the return value. + * + * If this component already exists on the given entity and the construction is successful, + * it is first destroyed as if destroy(utils::Entity e) was called. In case of error, + * the existing component is unmodified. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Result build(Engine& engine, utils::Entity entity); + + private: + friend class FEngine; + friend class FRenderPrimitive; + friend class FRenderableManager; + struct Entry { + VertexBuffer* UTILS_NULLABLE vertices = nullptr; + IndexBuffer* UTILS_NULLABLE indices = nullptr; + size_t offset = 0; + size_t count = 0; + MaterialInstance const* UTILS_NULLABLE materialInstance = nullptr; + PrimitiveType type = PrimitiveType::TRIANGLES; + uint16_t blendOrder = 0; + bool globalBlendOrderEnabled = false; + struct { + MorphTargetBuffer* UTILS_NULLABLE buffer = nullptr; + size_t offset = 0; + size_t count = 0; + } morphing; + }; + }; + + /** + * Destroys the renderable component in the given entity. + */ + void destroy(utils::Entity e) noexcept; + + /** + * Changes the bounding box used for frustum culling. + * + * \see Builder::boundingBox() + * \see RenderableManager::getAxisAlignedBoundingBox() + */ + void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept; + + /** + * Changes the visibility bits. + * + * \see Builder::layerMask() + * \see View::setVisibleLayers(). + * \see RenderableManager::getLayerMask() + */ + void setLayerMask(Instance instance, uint8_t select, uint8_t values) noexcept; + + /** + * Changes the coarse-level draw ordering. + * + * \see Builder::priority(). + */ + void setPriority(Instance instance, uint8_t priority) noexcept; + + /** + * Changes the channel a renderable is associated to. + * + * \see Builder::channel(). + */ + void setChannel(Instance instance, uint8_t channel) noexcept; + + /** + * Changes whether or not frustum culling is on. + * + * \see Builder::culling() + */ + void setCulling(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the large-scale fog is applied to this renderable + * @see Builder::fog() + */ + void setFogEnabled(Instance instance, bool enable) noexcept; + + /** + * Returns whether large-scale fog is enabled for this renderable. + * @return True if fog is enabled for this renderable. + * @see Builder::fog() + */ + bool getFogEnabled(Instance instance) const noexcept; + + /** + * Enables or disables a light channel. + * Light channel 0 is enabled by default. + * + * \see Builder::lightChannel() + */ + void setLightChannel(Instance instance, unsigned int channel, bool enable) noexcept; + + /** + * Returns whether a light channel is enabled on a specified renderable. + * @param instance Instance of the component obtained from getInstance(). + * @param channel Light channel to query + * @return true if the light channel is enabled, false otherwise + */ + bool getLightChannel(Instance instance, unsigned int channel) const noexcept; + + /** + * Changes whether or not the renderable casts shadows. + * + * \see Builder::castShadows() + */ + void setCastShadows(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the renderable can receive shadows. + * + * \see Builder::receiveShadows() + */ + void setReceiveShadows(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the renderable can use screen-space contact shadows. + * + * \see Builder::screenSpaceContactShadows() + */ + void setScreenSpaceContactShadows(Instance instance, bool enable) noexcept; + + /** + * Checks if the renderable can cast shadows. + * + * \see Builder::castShadows(). + */ + bool isShadowCaster(Instance instance) const noexcept; + + /** + * Checks if the renderable can receive shadows. + * + * \see Builder::receiveShadows(). + */ + bool isShadowReceiver(Instance instance) const noexcept; + + /** + * Updates the bone transforms in the range [offset, offset + boneCount). + * The bones must be pre-allocated using Builder::skinning(). + */ + void setBones(Instance instance, Bone const* UTILS_NONNULL transforms, + size_t boneCount = 1, size_t offset = 0); + + void setBones(Instance instance, math::mat4f const* UTILS_NONNULL transforms, + size_t boneCount = 1, size_t offset = 0); //!< \overload + + /** + * Associates a region of a SkinningBuffer to a renderable instance + * + * Note: due to hardware limitations offset + 256 must be smaller or equal to + * skinningBuffer->getBoneCount() + * + * @param instance Instance of the component obtained from getInstance(). + * @param skinningBuffer skinning buffer to associate to the instance + * @param count Size of the region in bones, must be smaller or equal to 256. + * @param offset Start offset of the region in bones + */ + void setSkinningBuffer(Instance instance, SkinningBuffer* UTILS_NONNULL skinningBuffer, + size_t count, size_t offset); + + /** + * Updates the vertex morphing weights on a renderable, all zeroes by default. + * + * The renderable must be built with morphing enabled, see Builder::morphing(). In legacy + * morphing mode, only the first 4 weights are considered. + * + * @param instance Instance of the component obtained from getInstance(). + * @param weights Pointer to morph target weights to be update. + * @param count Number of morph target weights. + * @param offset Index of the first morph target weight to set at instance. + */ + void setMorphWeights(Instance instance, + float const* UTILS_NONNULL weights, size_t count, size_t offset = 0); + + /** + * Associates a MorphTargetBuffer to the given primitive. + */ + void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, size_t offset, size_t count); + + /** + * Utility method to change a MorphTargetBuffer to the given primitive + */ + inline void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer); + + /** + * Get a MorphTargetBuffer to the given primitive or null if it doesn't exist. + */ + MorphTargetBuffer* UTILS_NULLABLE getMorphTargetBufferAt(Instance instance, + uint8_t level, size_t primitiveIndex) const noexcept; + + /** + * Gets the number of morphing in the given entity. + */ + size_t getMorphTargetCount(Instance instance) const noexcept; + + /** + * Gets the bounding box used for frustum culling. + * + * \see Builder::boundingBox() + * \see RenderableManager::setAxisAlignedBoundingBox() + */ + const Box& getAxisAlignedBoundingBox(Instance instance) const noexcept; + + /** + * Get the visibility bits. + * + * \see Builder::layerMask() + * \see View::setVisibleLayers(). + * \see RenderableManager::getLayerMask() + */ + uint8_t getLayerMask(Instance instance) const noexcept; + + /** + * Gets the immutable number of primitives in the given renderable. + */ + size_t getPrimitiveCount(Instance instance) const noexcept; + + /** + * Changes the material instance binding for the given primitive. + * + * The MaterialInstance's material must have a feature level equal or lower to the engine's + * selected feature level. + * + * @exception utils::PreConditionPanic if the engine doesn't support the material's + * feature level. + * + * @see Builder::material() + * @see Engine::setActiveFeatureLevel + */ + void setMaterialInstanceAt(Instance instance, + size_t primitiveIndex, MaterialInstance const* UTILS_NONNULL materialInstance); + + /** + * Retrieves the material instance that is bound to the given primitive. + */ + MaterialInstance* UTILS_NULLABLE getMaterialInstanceAt( + Instance instance, size_t primitiveIndex) const noexcept; + + /** + * Changes the geometry for the given primitive. + * + * \see Builder::geometry() + */ + void setGeometryAt(Instance instance, size_t primitiveIndex, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t count) noexcept; + + /** + * Changes the drawing order for blended primitives. The drawing order is either global or + * local (default) to this Renderable. In either case, the Renderable priority takes precedence. + * + * @param instance the renderable of interest + * @param primitiveIndex the primitive of interest + * @param order draw order number (0 by default). Only the lowest 15 bits are used. + * + * @see Builder::blendOrder(), setGlobalBlendOrderEnabledAt() + */ + void setBlendOrderAt(Instance instance, size_t primitiveIndex, uint16_t order) noexcept; + + /** + * Changes whether the blend order is global or local to this Renderable (by default). + * + * @param instance the renderable of interest + * @param primitiveIndex the primitive of interest + * @param enabled true for global, false for local blend ordering. + * + * @see Builder::globalBlendOrderEnabled(), setBlendOrderAt() + */ + void setGlobalBlendOrderEnabledAt(Instance instance, size_t primitiveIndex, bool enabled) noexcept; + + /** + * Retrieves the set of enabled attribute slots in the given primitive's VertexBuffer. + */ + AttributeBitset getEnabledAttributesAt(Instance instance, size_t primitiveIndex) const noexcept; + + /*! \cond PRIVATE */ + template + struct is_supported_vector_type { + using type = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type; + }; + + template + struct is_supported_index_type { + using type = typename std::enable_if< + std::is_same::value || + std::is_same::value + >::type; + }; + /*! \endcond */ + + /** + * Utility method that computes the axis-aligned bounding box from a set of vertices. + * + * - The index type must be \c uint16_t or \c uint32_t. + * - The vertex type must be \c float4, \c half4, \c float3, or \c half3. + * - For 4-component vertices, the w component is ignored (implicitly replaced with 1.0). + */ + template::type, + typename = typename is_supported_index_type::type> + static Box computeAABB( + VECTOR const* UTILS_NONNULL vertices, + INDEX const* UTILS_NONNULL indices, size_t count, + size_t stride = sizeof(VECTOR)) noexcept; + +protected: + // prevent heap allocation + ~RenderableManager() = default; +}; + +RenderableManager::Builder& RenderableManager::Builder::morphing( + uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept { + return morphing(level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); +} + +void RenderableManager::setMorphTargetBufferAt( + Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) { + setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); +} + +template +Box RenderableManager::computeAABB( + VECTOR const* UTILS_NONNULL vertices, + INDEX const* UTILS_NONNULL indices, + size_t count, size_t stride) noexcept { + math::float3 bmin(FLT_MAX); + math::float3 bmax(-FLT_MAX); + for (size_t i = 0; i < count; ++i) { + VECTOR const* p = reinterpret_cast( + (char const*)vertices + indices[i] * stride); + const math::float3 v(p->x, p->y, p->z); + bmin = min(bmin, v); + bmax = max(bmax, v); + } + return Box().set(bmin, bmax); +} + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERABLEMANAGER_H diff --git a/package/android/libs/filament/include/filament/Renderer.h b/package/android/libs/filament/include/filament/Renderer.h new file mode 100644 index 00000000..fdc291b1 --- /dev/null +++ b/package/android/libs/filament/include/filament/Renderer.h @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_RENDERER_H +#define TNT_FILAMENT_RENDERER_H + +#include + +#include + +#include + +#include + +namespace filament { + +class Engine; +class RenderTarget; +class SwapChain; +class View; +class Viewport; + +namespace backend { +class PixelBufferDescriptor; +} // namespace backend + +/** + * A Renderer instance represents an operating system's window. + * + * Typically, applications create a Renderer per window. The Renderer generates drawing commands + * for the render thread and manages frame latency. + * + * A Renderer generates drawing commands from a View, itself containing a Scene description. + * + * Creation and Destruction + * ======================== + * + * A Renderer is created using Engine.createRenderer() and destroyed using + * Engine.destroy(const Renderer*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * Renderer* renderer = engine->createRenderer(); + * engine->destroy(&renderer); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see Engine, View + */ +class UTILS_PUBLIC Renderer : public FilamentAPI { +public: + + /** + * Use DisplayInfo to set important Display properties. This is used to achieve correct + * frame pacing and dynamic resolution scaling. + */ + struct DisplayInfo { + // refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing. + float refreshRate = 60.0f; + + UTILS_DEPRECATED uint64_t presentationDeadlineNanos = 0; + UTILS_DEPRECATED uint64_t vsyncOffsetNanos = 0; + }; + + /** + * Use FrameRateOptions to set the desired frame rate and control how quickly the system + * reacts to GPU load changes. + * + * interval: desired frame interval in multiple of the refresh period, set in DisplayInfo + * (as 1 / DisplayInfo::refreshRate) + * + * The parameters below are relevant when some Views are using dynamic resolution scaling: + * + * headRoomRatio: additional headroom for the GPU as a ratio of the targetFrameTime. + * Useful for taking into account constant costs like post-processing or + * GPU drivers on different platforms. + * history: History size. higher values, tend to filter more (clamped to 31) + * scaleRate: rate at which the gpu load is adjusted to reach the target frame rate + * This value can be computed as 1 / N, where N is the number of frames + * needed to reach 64% of the target scale factor. + * Higher values make the dynamic resolution react faster. + * + * @see View::DynamicResolutionOptions + * @see Renderer::DisplayInfo + * + */ + struct FrameRateOptions { + float headRoomRatio = 0.0f; //!< additional headroom for the GPU + float scaleRate = 1.0f / 8.0f; //!< rate at which the system reacts to load changes + uint8_t history = 15; //!< history size + uint8_t interval = 1; //!< desired frame interval in unit of 1.0 / DisplayInfo::refreshRate + }; + + /** + * ClearOptions are used at the beginning of a frame to clear or retain the SwapChain content. + */ + struct ClearOptions { + /** + * Color (sRGB linear) to use to clear the RenderTarget (typically the SwapChain). + * + * The RenderTarget is cleared using this color, which won't be tone-mapped since + * tone-mapping is part of View rendering (this is not). + * + * When a View is rendered, there are 3 scenarios to consider: + * - Pixels rendered by the View replace the clear color (or blend with it in + * `BlendMode::TRANSLUCENT` mode). + * + * - With blending mode set to `BlendMode::TRANSLUCENT`, Pixels untouched by the View + * are considered fulling transparent and let the clear color show through. + * + * - With blending mode set to `BlendMode::OPAQUE`, Pixels untouched by the View + * are set to the clear color. However, because it is now used in the context of a View, + * it will go through the post-processing stage, which includes tone-mapping. + * + * For consistency, it is recommended to always use a Skybox to clear an opaque View's + * background, or to use black or fully-transparent (i.e. {0,0,0,0}) as the clear color. + */ + math::float4 clearColor = {}; + + /** Value to clear the stencil buffer */ + uint8_t clearStencil = 0u; + + /** + * Whether the SwapChain should be cleared using the clearColor. Use this if translucent + * View will be drawn, for instance. + */ + bool clear = false; + + /** + * Whether the SwapChain content should be discarded. clear implies discard. Set this + * to false (along with clear to false as well) if the SwapChain already has content that + * needs to be preserved + */ + bool discard = true; + }; + + /** + * Information about the display this Renderer is associated to. This information is needed + * to accurately compute dynamic-resolution scaling and for frame-pacing. + */ + void setDisplayInfo(const DisplayInfo& info) noexcept; + + /** + * Set options controlling the desired frame-rate. + */ + void setFrameRateOptions(FrameRateOptions const& options) noexcept; + + /** + * Set ClearOptions which are used at the beginning of a frame to clear or retain the + * SwapChain content. + */ + void setClearOptions(const ClearOptions& options); + + /** + * Returns the ClearOptions currently set. + * @return A reference to a ClearOptions structure. + */ + ClearOptions const& getClearOptions() const noexcept; + + /** + * Get the Engine that created this Renderer. + * + * @return A pointer to the Engine instance this Renderer is associated to. + */ + Engine* UTILS_NONNULL getEngine() noexcept; + + /** + * Get the Engine that created this Renderer. + * + * @return A constant pointer to the Engine instance this Renderer is associated to. + */ + inline Engine const* UTILS_NONNULL getEngine() const noexcept { + return const_cast(this)->getEngine(); + } + + /** + * Flags used to configure the behavior of copyFrame(). + * + * @see + * copyFrame() + */ + using CopyFrameFlag = uint32_t; + + /** + * Indicates that the dstSwapChain passed into copyFrame() should be + * committed after the frame has been copied. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag COMMIT = 0x1; + /** + * Indicates that the presentation time should be set on the dstSwapChain + * passed into copyFrame to the monotonic clock time when the frame is + * copied. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag SET_PRESENTATION_TIME = 0x2; + /** + * Indicates that the dstSwapChain passed into copyFrame() should be + * cleared to black before the frame is copied into the specified viewport. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag CLEAR = 0x4; + + + /** + * Set-up a frame for this Renderer. + * + * beginFrame() manages frame pacing, and returns whether or not a frame should be drawn. The + * goal of this is to skip frames when the GPU falls behind in order to keep the frame + * latency low. + * + * If a given frame takes too much time in the GPU, the CPU will get ahead of the GPU. The + * display will draw the same frame twice producing a stutter. At this point, the CPU is + * ahead of the GPU and depending on how many frames are buffered, latency increases. + * + * beginFrame() attempts to detect this situation and returns false in that case, indicating + * to the caller to skip the current frame. + * + * When beginFrame() returns true, it is mandatory to render the frame and call endFrame(). + * However, when beginFrame() returns false, the caller has the choice to either skip the + * frame and not call endFrame(), or proceed as though true was returned. + * + * @param vsyncSteadyClockTimeNano The time in nanosecond of when the current frame started, + * or 0 if unknown. This value should be the timestamp of + * the last h/w vsync. It is expressed in the + * std::chrono::steady_clock time base. + * @param swapChain A pointer to the SwapChain instance to use. + * + * @return + * *false* the current frame should be skipped, + * *true* the current frame must be drawn and endFrame() must be called. + * + * @remark + * When skipping a frame, the whole frame is canceled, and endFrame() must not be called. + * + * @note + * All calls to render() must happen *after* beginFrame(). + * + * @see + * endFrame() + */ + bool beginFrame(SwapChain* UTILS_NONNULL swapChain, + uint64_t vsyncSteadyClockTimeNano = 0u); + + /** + * Set the time at which the frame must be presented to the display. + * + * This must be called between beginFrame() and endFrame(). + * + * @param monotonic_clock_ns the time in nanoseconds corresponding to the system monotonic up-time clock. + * the presentation time is typically set in the middle of the period + * of interest. The presentation time cannot be too far in the + * future because it is limited by how many buffers are available in + * the display sub-system. Typically it is set to 1 or 2 vsync periods + * away. + */ + void setPresentationTime(int64_t monotonic_clock_ns); + + /** + * Render a View into this renderer's window. + * + * This is filament main rendering method, most of the CPU-side heavy lifting is performed + * here. render() main function is to generate render commands which are asynchronously + * executed by the Engine's render thread. + * + * render() generates commands for each of the following stages: + * + * 1. Shadow map passes, if needed. + * 2. Depth pre-pass. + * 3. Color pass. + * 4. Post-processing pass. + * + * A typical render loop looks like this: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * void renderLoop(Renderer* renderer, SwapChain* swapChain) { + * do { + * // typically we wait for VSYNC and user input events + * if (renderer->beginFrame(swapChain)) { + * renderer->render(mView); + * renderer->endFrame(); + * } + * } while (!quit()); + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * + * @param view A pointer to the view to render. + * + * @attention + * render() must be called *after* beginFrame() and *before* endFrame(). + * + * @note + * render() must be called from the Engine's main thread (or external synchronization + * must be provided). In particular, calls to render() on different Renderer instances + * **must** be synchronized. + * + * @remark + * render() perform potentially heavy computations and cannot be multi-threaded. However, + * internally, render() is highly multi-threaded to both improve performance in mitigate + * the call's latency. + * + * @remark + * render() is typically called once per frame (but not necessarily). + * + * @see + * beginFrame(), endFrame(), View + * + */ + void render(View const* UTILS_NONNULL view); + + /** + * Copy the currently rendered view to the indicated swap chain, using the + * indicated source and destination rectangle. + * + * @param dstSwapChain The swap chain into which the frame should be copied. + * @param dstViewport The destination rectangle in which to draw the view. + * @param srcViewport The source rectangle to be copied. + * @param flags One or more CopyFrameFlag behavior configuration flags. + * + * @remark + * copyFrame() should be called after a frame is rendered using render() + * but before endFrame() is called. + */ + void copyFrame(SwapChain* UTILS_NONNULL dstSwapChain, Viewport const& dstViewport, + Viewport const& srcViewport, uint32_t flags = 0); + + /** + * Reads back the content of the SwapChain associated with this Renderer. + * + * @param xoffset Left offset of the sub-region to read back. + * @param yoffset Bottom offset of the sub-region to read back. + * @param width Width of the sub-region to read back. + * @param height Height of the sub-region to read back. + * @param buffer Client-side buffer where the read-back will be written. + * + * The following formats are always supported: + * - PixelBufferDescriptor::PixelDataFormat::RGBA + * - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER + * + * The following types are always supported: + * - PixelBufferDescriptor::PixelDataType::UBYTE + * - PixelBufferDescriptor::PixelDataType::UINT + * - PixelBufferDescriptor::PixelDataType::INT + * - PixelBufferDescriptor::PixelDataType::FLOAT + * + * Other combinations of format/type may be supported. If a combination is + * not supported, this operation may fail silently. Use a DEBUG build + * to get some logs about the failure. + * + * + * Framebuffer as seen on User buffer (PixelBufferDescriptor&) + * screen + * + * +--------------------+ + * | | .stride .alignment + * | | ----------------------->--> + * | | O----------------------+--+ low addresses + * | | | | | | + * | w | | | .top | | + * | <---------> | | V | | + * | +---------+ | | +---------+ | | + * | | ^ | | ======> | | | | | + * | x | h| | | |.left| | | | + * +------>| v | | +---->| | | | + * | +.........+ | | +.........+ | | + * | ^ | | | | + * | y | | +----------------------+--+ high addresses + * O------------+-------+ + * + * + * readPixels() must be called within a frame, meaning after beginFrame() and before endFrame(). + * Typically, readPixels() will be called after render(). + * + * After issuing this method, the callback associated with `buffer` will be invoked on the + * main thread, indicating that the read-back has completed. Typically, this will happen + * after multiple calls to beginFrame(), render(), endFrame(). + * + * It is also possible to use a Fence to wait for the read-back. + * + * @remark + * readPixels() is intended for debugging and testing. It will impact performance significantly. + * + */ + void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + backend::PixelBufferDescriptor&& buffer); + + /** + * Finishes the current frame and schedules it for display. + * + * endFrame() schedules the current frame to be displayed on the Renderer's window. + * + * @note + * All calls to render() must happen *before* endFrame(). endFrame() must be called if + * beginFrame() returned true, otherwise, endFrame() must not be called unless the caller + * ignored beginFrame()'s return value. + * + * @see + * beginFrame() + */ + void endFrame(); + + + /** + * Reads back the content of the provided RenderTarget. + * + * @param renderTarget RenderTarget to read back from. + * @param xoffset Left offset of the sub-region to read back. + * @param yoffset Bottom offset of the sub-region to read back. + * @param width Width of the sub-region to read back. + * @param height Height of the sub-region to read back. + * @param buffer Client-side buffer where the read-back will be written. + * + * The following formats are always supported: + * - PixelBufferDescriptor::PixelDataFormat::RGBA + * - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER + * + * The following types are always supported: + * - PixelBufferDescriptor::PixelDataType::UBYTE + * - PixelBufferDescriptor::PixelDataType::UINT + * - PixelBufferDescriptor::PixelDataType::INT + * - PixelBufferDescriptor::PixelDataType::FLOAT + * + * Other combinations of format/type may be supported. If a combination is + * not supported, this operation may fail silently. Use a DEBUG build + * to get some logs about the failure. + * + * + * Framebuffer as seen on User buffer (PixelBufferDescriptor&) + * screen + * + * +--------------------+ + * | | .stride .alignment + * | | ----------------------->--> + * | | O----------------------+--+ low addresses + * | | | | | | + * | w | | | .top | | + * | <---------> | | V | | + * | +---------+ | | +---------+ | | + * | | ^ | | ======> | | | | | + * | x | h| | | |.left| | | | + * +------>| v | | +---->| | | | + * | +.........+ | | +.........+ | | + * | ^ | | | | + * | y | | +----------------------+--+ high addresses + * O------------+-------+ + * + * + * Typically readPixels() will be called after render() and before endFrame(). + * + * After issuing this method, the callback associated with `buffer` will be invoked on the + * main thread, indicating that the read-back has completed. Typically, this will happen + * after multiple calls to beginFrame(), render(), endFrame(). + * + * It is also possible to use a Fence to wait for the read-back. + * + * OpenGL only: if issuing a readPixels on a RenderTarget backed by a Texture that had data + * uploaded to it via setImage, the data returned from readPixels will be y-flipped with respect + * to the setImage call. + * + * @remark + * readPixels() is intended for debugging and testing. It will impact performance significantly. + * + */ + void readPixels(RenderTarget* UTILS_NONNULL renderTarget, + uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + backend::PixelBufferDescriptor&& buffer); + + /** + * Render a standalone View into its associated RenderTarget + * + * This call is mostly equivalent to calling render(View*) inside a + * beginFrame / endFrame block, but incurs less overhead. It can be used + * as a poor man's compute API. + * + * @param view A pointer to the view to render. This View must have a RenderTarget associated + * to it. + * + * @attention + * renderStandaloneView() must be called outside of beginFrame() / endFrame(). + * + * @note + * renderStandaloneView() must be called from the Engine's main thread + * (or external synchronization must be provided). In particular, calls to + * renderStandaloneView() on different Renderer instances **must** be synchronized. + * + * @remark + * renderStandaloneView() perform potentially heavy computations and cannot be multi-threaded. + * However, internally, renderStandaloneView() is highly multi-threaded to both improve + * performance in mitigate the call's latency. + */ + void renderStandaloneView(View const* UTILS_NONNULL view); + + + /** + * Returns the time in second of the last call to beginFrame(). This value is constant for all + * views rendered during a frame. The epoch is set with resetUserTime(). + * + * In materials, this value can be queried using `vec4 getUserTime()`. The value returned + * is a highp vec4 encoded as follows: + * + * time.x = (float)Renderer.getUserTime(); + * time.y = Renderer.getUserTime() - time.x; + * + * It follows that the following invariants are true: + * + * (double)time.x + (double)time.y == Renderer.getUserTime() + * time.x == (float)Renderer.getUserTime() + * + * This encoding allows the shader code to perform high precision (i.e. double) time + * calculations when needed despite the lack of double precision in the shader, for e.g.: + * + * To compute (double)time * vertex in the material, use the following construct: + * + * vec3 result = time.x * vertex + time.y * vertex; + * + * + * Most of the time, high precision computations are not required, but be aware that the + * precision of time.x rapidly diminishes as time passes: + * + * time | precision + * --------+---------- + * 16.7s | us + * 4h39 | ms + * 77h | 1/60s + * + * + * In other words, it only possible to get microsecond accuracy for about 16s or millisecond + * accuracy for just under 5h. + * + * This problem can be mitigated by calling resetUserTime(), or using high precision time as + * described above. + * + * @return The time is seconds since resetUserTime() was last called. + * + * @see + * resetUserTime() + */ + double getUserTime() const; + + /** + * Sets the user time epoch to now, i.e. resets the user time to zero. + * + * Use this method used to keep the precision of time high in materials, in practice it should + * be called at least when the application is paused, e.g. Activity.onPause() in Android. + * + * @see + * getUserTime() + */ + void resetUserTime(); + +protected: + // prevent heap allocation + ~Renderer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERER_H diff --git a/package/android/libs/filament/include/filament/Scene.h b/package/android/libs/filament/include/filament/Scene.h new file mode 100644 index 00000000..9df6285c --- /dev/null +++ b/package/android/libs/filament/include/filament/Scene.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_SCENE_H +#define TNT_FILAMENT_SCENE_H + +#include + +#include +#include + +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class IndirectLight; +class Skybox; + +/** + * A Scene is a flat container of Renderable and Light instances. + * + * A Scene doesn't provide a hierarchy of Renderable objects, i.e.: it's not a scene-graph. + * However, it manages the list of objects to render and the list of lights. Renderable + * and Light objects can be added or removed from a Scene at any time. + * + * A Renderable *must* be added to a Scene in order to be rendered, and the Scene must be + * provided to a View. + * + * + * Creation and Destruction + * ======================== + * + * A Scene is created using Engine.createScene() and destroyed using + * Engine.destroy(const Scene*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * Scene* scene = engine->createScene(); + * engine->destroy(&scene); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see View, Renderable, Light + */ +class UTILS_PUBLIC Scene : public FilamentAPI { +public: + + /** + * Sets the Skybox. + * + * The Skybox is drawn last and covers all pixels not touched by geometry. + * + * @param skybox The Skybox to use to fill untouched pixels, or nullptr to unset the Skybox. + */ + void setSkybox(Skybox* UTILS_NULLABLE skybox) noexcept; + + /** + * Returns the Skybox associated with the Scene. + * + * @return The associated Skybox, or nullptr if there is none. + */ + Skybox* UTILS_NULLABLE getSkybox() const noexcept; + + /** + * Set the IndirectLight to use when rendering the Scene. + * + * Currently, a Scene may only have a single IndirectLight. This call replaces the current + * IndirectLight. + * + * @param ibl The IndirectLight to use when rendering the Scene or nullptr to unset. + * @see getIndirectLight + */ + void setIndirectLight(IndirectLight* UTILS_NULLABLE ibl) noexcept; + + /** + * Get the IndirectLight or nullptr if none is set. + * + * @return the the IndirectLight or nullptr if none is set + * @see setIndirectLight + */ + IndirectLight* UTILS_NULLABLE getIndirectLight() const noexcept; + + /** + * Adds an Entity to the Scene. + * + * @param entity The entity is ignored if it doesn't have a Renderable or Light component. + * + * \attention + * A given Entity object can only be added once to a Scene. + * + */ + void addEntity(utils::Entity entity); + + /** + * Adds a list of entities to the Scene. + * + * @param entities Array containing entities to add to the scene. + * @param count Size of the entity array. + */ + void addEntities(const utils::Entity* UTILS_NONNULL entities, size_t count); + + /** + * Removes the Renderable from the Scene. + * + * @param entity The Entity to remove from the Scene. If the specified + * \p entity doesn't exist, this call is ignored. + */ + void remove(utils::Entity entity); + + /** + * Removes a list of entities to the Scene. + * + * This is equivalent to calling remove in a loop. + * If any of the specified entities do not exist in the scene, they are skipped. + * + * @param entities Array containing entities to remove from the scene. + * @param count Size of the entity array. + */ + void removeEntities(const utils::Entity* UTILS_NONNULL entities, size_t count); + + /** + * Returns the total number of Entities in the Scene, whether alive or not. + * @return Total number of Entities in the Scene. + */ + size_t getEntityCount() const noexcept; + + /** + * Returns the number of active (alive) Renderable objects in the Scene. + * + * @return The number of active (alive) Renderable objects in the Scene. + */ + size_t getRenderableCount() const noexcept; + + /** + * Returns the number of active (alive) Light objects in the Scene. + * + * @return The number of active (alive) Light objects in the Scene. + */ + size_t getLightCount() const noexcept; + + /** + * Returns true if the given entity is in the Scene. + * + * @return Whether the given entity is in the Scene. + */ + bool hasEntity(utils::Entity entity) const noexcept; + + /** + * Invokes user functor on each entity in the scene. + * + * It is not allowed to add or remove an entity from the scene within the functor. + * + * @param functor User provided functor called for each entity in the scene + */ + void forEach(utils::Invocable&& functor) const noexcept; + +protected: + // prevent heap allocation + ~Scene() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SCENE_H diff --git a/package/android/libs/filament/include/filament/SkinningBuffer.h b/package/android/libs/filament/include/filament/SkinningBuffer.h new file mode 100644 index 00000000..36ae30ed --- /dev/null +++ b/package/android/libs/filament/include/filament/SkinningBuffer.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_SKINNINGBUFFER_H +#define TNT_FILAMENT_SKINNINGBUFFER_H + +#include + +#include + +#include + +#include + +#include +#include + +namespace filament { + +/** + * SkinningBuffer is used to hold skinning data (bones). It is a simple wraper around + * a structured UBO. + * @see RenderableManager::setSkinningBuffer + */ +class UTILS_PUBLIC SkinningBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the skinning buffer in bones. + * + * Due to limitation in the GLSL, the SkinningBuffer must always by a multiple of + * 256, this adjustment is done automatically, but can cause + * some memory overhead. This memory overhead can be mitigated by using the same + * SkinningBuffer to store the bone information for multiple RenderPrimitives. + * + * @param boneCount Number of bones the skinning buffer can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& boneCount(uint32_t boneCount) noexcept; + + /** + * The new buffer is created with identity bones + * @param initialize true to initializing the buffer, false to not. + * @return A reference to this Builder for chaining calls. + */ + Builder& initialize(bool initialize = true) noexcept; + + /** + * Creates the SkinningBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see SkinningBuffer::setBones + */ + SkinningBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FSkinningBuffer; + }; + + /** + * Updates the bone transforms in the range [offset, offset + count). + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * @param transforms pointer to at least count Bone + * @param count number of Bone elements in transforms + * @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms) + * @see RenderableManager::setSkinningBuffer + */ + void setBones(Engine& engine, RenderableManager::Bone const* UTILS_NONNULL transforms, + size_t count, size_t offset = 0); + + /** + * Updates the bone transforms in the range [offset, offset + count). + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * @param transforms pointer to at least count mat4f + * @param count number of mat4f elements in transforms + * @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms) + * @see RenderableManager::setSkinningBuffer + */ + void setBones(Engine& engine, math::mat4f const* UTILS_NONNULL transforms, + size_t count, size_t offset = 0); + + /** + * Returns the size of this SkinningBuffer in elements. + * @return The number of bones the SkinningBuffer holds. + */ + size_t getBoneCount() const noexcept; + +protected: + // prevent heap allocation + ~SkinningBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_SKINNINGBUFFER_H diff --git a/package/android/libs/filament/include/filament/Skybox.h b/package/android/libs/filament/include/filament/Skybox.h new file mode 100644 index 00000000..ce203aae --- /dev/null +++ b/package/android/libs/filament/include/filament/Skybox.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_SKYBOX_H +#define TNT_FILAMENT_SKYBOX_H + +#include + +#include + +#include + +#include + +namespace filament { + +class FSkybox; + +class Engine; +class Texture; + +/** + * Skybox + * + * When added to a Scene, the Skybox fills all untouched pixels. + * + * Creation and destruction + * ======================== + * + * A Skybox object is created using the Skybox::Builder and destroyed by calling + * Engine::destroy(const Skybox*). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::IndirectLight* skybox = filament::Skybox::Builder() + * .environment(cubemap) + * .build(*engine); + * + * engine->destroy(skybox); + * ~~~~~~~~~~~ + * + * + * @note + * Currently only Texture based sky boxes are supported. + * + * @see Scene, IndirectLight + */ +class UTILS_PUBLIC Skybox : public FilamentAPI { + struct BuilderDetails; + +public: + //! Use Builder to construct an Skybox object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Set the environment map (i.e. the skybox content). + * + * The Skybox is rendered as though it were an infinitely large cube with the camera + * inside it. This means that the cubemap which is mapped onto the cube's exterior + * will appear mirrored. This follows the OpenGL conventions. + * + * The cmgen tool generates reflection maps by default which are therefore ideal to use + * as skyboxes. + * + * @param cubemap This Texture must be a cube map. + * + * @return This Builder, for chaining calls. + * + * @see Texture + */ + Builder& environment(Texture* UTILS_NONNULL cubemap) noexcept; + + /** + * Indicates whether the sun should be rendered. The sun can only be + * rendered if there is at least one light of type SUN in the scene. + * The default value is false. + * + * @param show True if the sun should be rendered, false otherwise + * + * @return This Builder, for chaining calls. + */ + Builder& showSun(bool show) noexcept; + + /** + * Skybox intensity when no IndirectLight is set on the Scene. + * + * This call is ignored when an IndirectLight is set on the Scene, and the intensity + * of the IndirectLight is used instead. + * + * @param envIntensity Scale factor applied to the skybox texel values such that + * the result is in lux, or lumen/m^2 (default = 30000) + * + * @return This Builder, for chaining calls. + * + * @see IndirectLight::Builder::intensity + */ + Builder& intensity(float envIntensity) noexcept; + + /** + * Sets the skybox to a constant color. Default is opaque black. + * + * Ignored if an environment is set. + * + * @param color the constant color + * + * @return This Builder, for chaining calls. + */ + Builder& color(math::float4 color) noexcept; + + /** + * Creates the Skybox object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Skybox with. + * + * @return pointer to the newly created object. + */ + Skybox* UTILS_NONNULL build(Engine& engine); + + private: + friend class FSkybox; + }; + + void setColor(math::float4 color) noexcept; + + /** + * Sets bits in a visibility mask. By default, this is 0x1. + * + * This provides a simple mechanism for hiding or showing this Skybox in a Scene. + * + * @see View::setVisibleLayers(). + * + * For example, to set bit 1 and reset bits 0 and 2 while leaving all other bits unaffected, + * call: `setLayerMask(7, 2)`. + * + * @param select the set of bits to affect + * @param values the replacement values for the affected bits + */ + void setLayerMask(uint8_t select, uint8_t values) noexcept; + + /** + * @return the visibility mask bits + */ + uint8_t getLayerMask() const noexcept; + + /** + * Returns the skybox's intensity in lux, or lumen/m^2. + */ + float getIntensity() const noexcept; + + /** + * @return the associated texture + */ + Texture const* UTILS_NONNULL getTexture() const noexcept; + +protected: + // prevent heap allocation + ~Skybox() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SKYBOX_H diff --git a/package/android/libs/filament/include/filament/Stream.h b/package/android/libs/filament/include/filament/Stream.h new file mode 100644 index 00000000..6cafbacc --- /dev/null +++ b/package/android/libs/filament/include/filament/Stream.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_STREAM_H +#define TNT_FILAMENT_STREAM_H + +#include + +#include +#include + +#include + +#include + +namespace filament { + +class FStream; + +class Engine; + +/** + * Stream is used to attach a video stream to a Filament `Texture`. + * + * Note that the `Stream` class is fairly Android centric. It supports two different + * configurations: + * + * - ACQUIRED.....connects to an Android AHardwareBuffer + * - NATIVE.......connects to an Android SurfaceTexture + * + * Before explaining these different configurations, let's review the high-level structure of an AR + * or video application that uses Filament: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * while (true) { + * + * // Misc application work occurs here, such as: + * // - Writing the image data for a video frame into a Stream + * // - Moving the Filament Camera + * + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Let's say that the video image data at the time of a particular invocation of `beginFrame` + * becomes visible to users at time A. The 3D scene state (including the camera) at the time of + * that same invocation becomes apparent to users at time B. + * + * - If time A matches time B, we say that the stream is \em{synchronized}. + * - Filament invokes low-level graphics commands on the \em{driver thread}. + * - The thread that calls `beginFrame` is called the \em{main thread}. + * + * For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires + * the stream, then releases it later via a callback function. This configuration is especially + * useful when the Vulkan backend is enabled. + * + * For NATIVE streams, Filament does not make any synchronization guarantee. However they are simple + * to use and do not incur a copy. These are often appropriate in video applications. + * + * Please see `sample-stream-test` and `sample-hello-camera` for usage examples. + * + * @see backend::StreamType + * @see Texture#setExternalStream + * @see Engine#destroyStream + */ +class UTILS_PUBLIC Stream : public FilamentAPI { + struct BuilderDetails; + +public: + using Callback = backend::StreamCallback; + using StreamType = backend::StreamType; + + /** + * Constructs a Stream object instance. + * + * By default, Stream objects are ACQUIRED and must have external images pushed to them via + *
Stream::setAcquiredImage
. + * + * To create a NATIVE stream, call the
stream
method on the builder. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Creates a NATIVE stream. Native streams can sample data directly from an + * opaque platform object such as a SurfaceTexture on Android. + * + * @param stream An opaque native stream handle. e.g.: on Android this is an + * `android/graphics/SurfaceTexture` JNI jobject. The wrap mode must + * be CLAMP_TO_EDGE. + * + * @return This Builder, for chaining calls. + */ + Builder& stream(void* UTILS_NULLABLE stream) noexcept; + + /** + * + * @param width initial width of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @return This Builder, for chaining calls. + */ + Builder& width(uint32_t width) noexcept; + + /** + * + * @param height initial height of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @return This Builder, for chaining calls. + */ + Builder& height(uint32_t height) noexcept; + + /** + * Creates the Stream object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Stream with. + * + * @return pointer to the newly created object. + */ + Stream* UTILS_NONNULL build(Engine& engine); + + private: + friend class FStream; + }; + + /** + * Indicates whether this stream is a NATIVE stream or ACQUIRED stream. + */ + StreamType getStreamType() const noexcept; + + /** + * Updates an ACQUIRED stream with an image that is guaranteed to be used in the next frame. + * + * This method tells Filament to immediately "acquire" the image and trigger a callback + * when it is done with it. This should be called by the user outside of beginFrame / endFrame, + * and should be called only once per frame. If the user pushes images to the same stream + * multiple times in a single frame, only the final image is honored, but all callbacks are + * invoked. + * + * This method should be called on the same thread that calls Renderer::beginFrame, which is + * also where the callback is invoked. This method can only be used for streams that were + * constructed without calling the `stream` method on the builder. + * + * @see Stream for more information about NATIVE and ACQUIRED configurations. + * + * @param image Pointer to AHardwareBuffer, casted to void* since this is a public header. + * @param callback This is triggered by Filament when it wishes to release the image. + * The callback tales two arguments: the AHardwareBuffer and the userdata. + * @param userdata Optional closure data. Filament will pass this into the callback when it + * releases the image. + */ + void setAcquiredImage(void* UTILS_NONNULL image, + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + + /** + * @see setAcquiredImage(void*, Callback, void*) + * + * @param image Pointer to AHardwareBuffer, casted to void* since this is a public header. + * @param handler Handler to dispatch the AcquiredImage or nullptr for the default handler. + * @param callback This is triggered by Filament when it wishes to release the image. + * It callback tales two arguments: the AHardwareBuffer and the userdata. + * @param userdata Optional closure data. Filament will pass this into the callback when it + * releases the image. + */ + void setAcquiredImage(void* UTILS_NONNULL image, + backend::CallbackHandler* UTILS_NULLABLE handler, + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + + /** + * Updates the size of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @param width new width of the incoming stream + * @param height new height of the incoming stream + */ + void setDimensions(uint32_t width, uint32_t height) noexcept; + + /** + * Returns the presentation time of the currently displayed frame in nanosecond. + * + * This value can change at any time. + * + * @return timestamp in nanosecond. + */ + int64_t getTimestamp() const noexcept; + +protected: + // prevent heap allocation + ~Stream() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_STREAM_H diff --git a/package/android/libs/filament/include/filament/SwapChain.h b/package/android/libs/filament/include/filament/SwapChain.h new file mode 100644 index 00000000..8db477ad --- /dev/null +++ b/package/android/libs/filament/include/filament/SwapChain.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_SWAPCHAIN_H +#define TNT_FILAMENT_SWAPCHAIN_H + +#include + +#include +#include + +#include +#include + +#include + +namespace filament { + +class Engine; + +/** + * A swap chain represents an Operating System's *native* renderable surface. + * + * Typically it's a native window or a view. Because a SwapChain is initialized from a + * native object, it is given to filament as a `void *`, which must be of the proper type + * for each platform filament is running on. + * + * \code + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * \endcode + * + * When Engine::create() is used without specifying a Platform, the `nativeWindow` + * parameter above must be of type: + * + * Platform | nativeWindow type + * :---------------|:----------------------------: + * Android | ANativeWindow* + * macOS - OpenGL | NSView* + * macOS - Metal | CAMetalLayer* + * iOS - OpenGL | CAEAGLLayer* + * iOS - Metal | CAMetalLayer* + * X11 | Window + * Windows | HWND + * + * Otherwise, the `nativeWindow` is defined by the concrete implementation of Platform. + * + * + * Examples: + * + * Android + * ------- + * + * On Android, an `ANativeWindow*` can be obtained from a Java `Surface` object using: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * // parameters + * // env: JNIEnv* + * // surface: jobject + * ANativeWindow* win = ANativeWindow_fromSurface(env, surface); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \warning + * Don't use reflection to access the `mNativeObject` field, it won't work. + * + * A `Surface` can be retrieved from a `SurfaceView` or `SurfaceHolder` easily using + * `SurfaceHolder.getSurface()` and/or `SurfaceView.getHolder()`. + * + * \note + * To use a `TextureView` as a SwapChain, it is necessary to first get its `SurfaceTexture`, + * for instance using `TextureView.SurfaceTextureListener` and then create a `Surface`: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java} + * // using a TextureView.SurfaceTextureListener: + * public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { + * mSurface = new Surface(surfaceTexture); + * // mSurface can now be used in JNI to create an ANativeWindow. + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Linux + * ----- + * + * Example using SDL: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * SDL_GetWindowWMInfo(sdlWindow, &wmi); + * Window nativeWindow = (Window) wmi.info.x11.window; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Windows + * ------- + * + * Example using SDL: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * ASSERT_POSTCONDITION(SDL_GetWindowWMInfo(sdlWindow, &wmi), "SDL version unsupported!"); + * HDC nativeWindow = (HDC) wmi.info.win.hdc; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * OSX + * --- + * + * On OSX, any `NSView` can be used *directly* as a `nativeWindow` with createSwapChain(). + * + * Example using SDL/Objective-C: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.mm} + * #include + * + * #include + * #include + * + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * NSWindow* win = (NSWindow*) wmi.info.cocoa.window; + * NSView* view = [win contentView]; + * void* nativeWindow = view; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see Engine + */ +class UTILS_PUBLIC SwapChain : public FilamentAPI { +public: + using FrameScheduledCallback = backend::FrameScheduledCallback; + using FrameCompletedCallback = utils::Invocable; + + /** + * Requests a SwapChain with an alpha channel. + */ + static const uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT; + + /** + * This flag indicates that the swap chain may be used as a source surface + * for reading back render results. This config must be set when creating + * any swap chain that will be used as the source for a blit operation. + * + * @see + * Renderer.copyFrame() + */ + static const uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE; + + /** + * Indicates that the native X11 window is an XCB window rather than an XLIB window. + * This is ignored on non-Linux platforms and in builds that support only one X11 API. + */ + static const uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB; + + /** + * Indicates that the native window is a CVPixelBufferRef. + * + * This is only supported by the Metal backend. The CVPixelBuffer must be in the + * kCVPixelFormatType_32BGRA format. + * + * It is not necessary to add an additional retain call before passing the pixel buffer to + * Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and + * CVPixelBufferRelease when the swap chain is destroyed. + */ + static const uint64_t CONFIG_APPLE_CVPIXELBUFFER = + backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER; + + /** + * Indicates that the SwapChain must automatically perform linear to sRGB encoding. + * + * This flag is ignored if isSRGBSwapChainSupported() is false. + * + * When using this flag, the output colorspace in ColorGrading should be set to + * Rec709-Linear-D65, or post-processing should be disabled. + * + * @see isSRGBSwapChainSupported() + * @see ColorGrading.outputColorSpace() + * @see View.setPostProcessingEnabled() + */ + static constexpr uint64_t CONFIG_SRGB_COLORSPACE = backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE; + + /** + * Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer. + * + * This flag is necessary when using View::setStencilBufferEnabled and rendering directly into + * the SwapChain (when post-processing is disabled). + * + * The specific format of the stencil buffer depends on platform support. The following pixel + * formats are tried, in order of preference: + * + * Depth only (without CONFIG_HAS_STENCIL_BUFFER): + * - DEPTH32F + * - DEPTH24 + * + * Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER): + * - DEPTH32F_STENCIL8 + * - DEPTH24F_STENCIL8 + * + * Note that enabling the stencil buffer may hinder depth precision and should only be used if + * necessary. + * + * @see View.setStencilBufferEnabled + * @see View.setPostProcessingEnabled + */ + static constexpr uint64_t CONFIG_HAS_STENCIL_BUFFER = backend::SWAP_CHAIN_HAS_STENCIL_BUFFER; + + /** + * Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag. + * The default implementation returns false. + * + * @param engine A pointer to the filament Engine + * @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise. + */ + static bool isSRGBSwapChainSupported(Engine& engine) noexcept; + + void* UTILS_NULLABLE getNativeWindow() const noexcept; + + /** + * FrameScheduledCallback is a callback function that notifies an application when Filament has + * completed processing a frame and that frame is ready to be scheduled for presentation. + * + * Typically, Filament is responsible for scheduling the frame's presentation to the SwapChain. + * If a SwapChain::FrameScheduledCallback is set, however, the application bares the + * responsibility of scheduling a frame for presentation by calling the backend::PresentCallable + * passed to the callback function. Currently this functionality is only supported by the Metal + * backend. + * + * A FrameScheduledCallback can be set on an individual SwapChain through + * SwapChain::setFrameScheduledCallback. If the callback is set, then the SwapChain will *not* + * automatically schedule itself for presentation. Instead, the application must call the + * PresentCallable passed to the FrameScheduledCallback. + * + * If your application delays the call to the PresentCallable by, for example, calling it on a + * separate thread, you must ensure all PresentCallables have been called before shutting down + * the Filament Engine. You can do this by issuing an Engine::flushAndWait before calling + * Engine::shutdown. This is necessary to ensure the Filament Engine has had a chance to clean + * up all memory related to frame presentation. + * + * @param callback A callback, or nullptr to unset. + * @param user An optional pointer to user data passed to the callback function. + * + * @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other + * backends ignore the callback (which will never be called) and proceed normally. + * + * @remark The SwapChain::FrameScheduledCallback is called on an arbitrary thread. + * + * @see PresentCallable + */ + void setFrameScheduledCallback(FrameScheduledCallback UTILS_NULLABLE callback, + void* UTILS_NULLABLE user = nullptr); + + /** + * FrameCompletedCallback is a callback function that notifies an application when a frame's + * contents have completed rendering on the GPU. + * + * Use SwapChain::setFrameCompletedCallback to set a callback on an individual SwapChain. Each + * time a frame completes GPU rendering, the callback will be called. + * + * If handler is nullptr, the callback is guaranteed to be called on the main Filament thread. + * + * Use \c setFrameCompletedCallback() (with default arguments) to unset the callback. + * + * @param handler Handler to dispatch the callback or nullptr for the default handler. + * @param callback Callback called when each frame completes. + * + * @remark Only Filament's Metal backend supports frame callbacks. Other backends ignore the + * callback (which will never be called) and proceed normally. + * + * @see CallbackHandler + */ + void setFrameCompletedCallback(backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + FrameCompletedCallback&& callback = {}) noexcept; + + +protected: + // prevent heap allocation + ~SwapChain() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SWAPCHAIN_H diff --git a/package/android/libs/filament/include/filament/Texture.h b/package/android/libs/filament/include/filament/Texture.h new file mode 100644 index 00000000..1b7c39ea --- /dev/null +++ b/package/android/libs/filament/include/filament/Texture.h @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_TEXTURE_H +#define TNT_FILAMENT_TEXTURE_H + +#include + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +class FTexture; + +class Engine; +class Stream; + +/** + * Texture + * + * The Texture class supports: + * - 2D textures + * - 3D textures + * - Cube maps + * - mip mapping + * + * + * Creation and destruction + * ======================== + * + * A Texture object is created using the Texture::Builder and destroyed by calling + * Engine::destroy(const Texture*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::Texture* texture = filament::Texture::Builder() + * .width(64) + * .height(64) + * .build(*engine); + * + * engine->destroy(texture); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +class UTILS_PUBLIC Texture : public FilamentAPI { + struct BuilderDetails; + +public: + static constexpr const size_t BASE_LEVEL = 0; + + //! Face offsets for all faces of a cubemap + struct FaceOffsets; + + using PixelBufferDescriptor = backend::PixelBufferDescriptor; //!< Geometry of a pixel buffer + using Sampler = backend::SamplerType; //!< Type of sampler + using InternalFormat = backend::TextureFormat; //!< Internal texel format + using CubemapFace = backend::TextureCubemapFace; //!< Cube map faces + using Format = backend::PixelDataFormat; //!< Pixel color format + using Type = backend::PixelDataType; //!< Pixel data format + using CompressedType = backend::CompressedPixelDataType; //!< Compressed pixel data format + using Usage = backend::TextureUsage; //!< Usage affects texel layout + using Swizzle = backend::TextureSwizzle; //!< Texture swizzle + + /** @return whether a backend supports a particular format. */ + static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept; + + /** @return whether a backend supports texture swizzling. */ + static bool isTextureSwizzleSupported(Engine& engine) noexcept; + + static size_t computeTextureDataSize(Texture::Format format, Texture::Type type, + size_t stride, size_t height, size_t alignment) noexcept; + + + /** + * Options for environment prefiltering into reflection map + * + * @see generatePrefilterMipmap() + */ + struct PrefilterOptions { + uint16_t sampleCount = 8; //!< sample count used for filtering + bool mirror = true; //!< whether the environment must be mirrored + private: + UTILS_UNUSED uintptr_t reserved[3] = {}; + }; + + + //! Use Builder to construct a Texture object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Specifies the width in texels of the texture. Doesn't need to be a power-of-two. + * @param width Width of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + */ + Builder& width(uint32_t width) noexcept; + + /** + * Specifies the height in texels of the texture. Doesn't need to be a power-of-two. + * @param height Height of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + */ + Builder& height(uint32_t height) noexcept; + + /** + * Specifies the depth in texels of the texture. Doesn't need to be a power-of-two. + * The depth controls the number of layers in a 2D array texture. Values greater than 1 + * effectively create a 3D texture. + * @param depth Depth of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + * @attention This Texture instance must use Sampler::SAMPLER_3D or + * Sampler::SAMPLER_2D_ARRAY or it has no effect. + */ + Builder& depth(uint32_t depth) noexcept; + + /** + * Specifies the numbers of mip map levels. + * This creates a mip-map pyramid. The maximum number of levels a texture can have is + * such that max(width, height, level) / 2^MAX_LEVELS = 1 + * @param levels Number of mipmap levels for this texture. + * @return This Builder, for chaining calls. + */ + Builder& levels(uint8_t levels) noexcept; + + /** + * Specifies the type of sampler to use. + * @param target Sampler type + * @return This Builder, for chaining calls. + * @see Sampler + */ + Builder& sampler(Sampler target) noexcept; + + /** + * Specifies the *internal* format of this texture. + * + * The internal format specifies how texels are stored (which may be different from how + * they're specified in setImage()). InternalFormat specifies both the color components + * and the data type used. + * + * @param format Format of the texture's texel. + * @return This Builder, for chaining calls. + * @see InternalFormat, setImage + */ + Builder& format(InternalFormat format) noexcept; + + /** + * Specifies if the texture will be used as a render target attachment. + * + * If the texture is potentially rendered into, it may require a different memory layout, + * which needs to be known during construction. + * + * @param usage Defaults to Texture::Usage::DEFAULT; c.f. Texture::Usage::COLOR_ATTACHMENT. + * @return This Builder, for chaining calls. + */ + Builder& usage(Usage usage) noexcept; + + /** + * Specifies how a texture's channels map to color components + * + * Texture Swizzle is only supported if isTextureSwizzleSupported() returns true. + * + * @param r texture channel for red component + * @param g texture channel for green component + * @param b texture channel for blue component + * @param a texture channel for alpha component + * @return This Builder, for chaining calls. + * @see Texture::isTextureSwizzleSupported() + */ + Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept; + + /** + * Creates the Texture object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Texture with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Texture* UTILS_NONNULL build(Engine& engine); + + /* no user serviceable parts below */ + + /** + * Specify a native texture to import as a Filament texture. + * + * The texture id is backend-specific: + * - OpenGL: GLuint texture ID + * - Metal: id + * + * With Metal, the id object should be cast to an intptr_t using + * CFBridgingRetain to transfer ownership to Filament. Filament will release ownership of + * the texture object when the Filament texture is destroyed. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + * id metalTexture = ... + * filamentTexture->import((intptr_t) CFBridgingRetain(metalTexture)); + * // free to release metalTexture + * + * // after using texture: + * engine->destroy(filamentTexture); // metalTexture is released + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @warning This method should be used as a last resort. This API is subject to change or + * removal. + * + * @param id a backend specific texture identifier + * + * @return This Builder, for chaining calls. + */ + Builder& import(intptr_t id) noexcept; + + private: + friend class FTexture; + }; + + /** + * Returns the width of a 2D or 3D texture level + * @param level texture level. + * @return Width in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getWidth(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the height of a 2D or 3D texture level + * @param level texture level. + * @return Height in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getHeight(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the depth of a 3D texture level + * @param level texture level. + * @return Depth in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getDepth(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the maximum number of levels this texture can have. + * @return maximum number of levels this texture can have. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getLevels() const noexcept; + + /** + * Return this texture Sampler as set by Builder::sampler(). + * @return this texture Sampler as set by Builder::sampler() + */ + Sampler getTarget() const noexcept; + + /** + * Return this texture InternalFormat as set by Builder::format(). + * @return this texture InternalFormat as set by Builder::format(). + */ + InternalFormat getFormat() const noexcept; + + /** + * Updates a sub-image of a 3D texture or 2D texture array for a level. Cubemaps are treated + * like a 2D array of six layers. + * + * @param engine Engine this texture is associated to. + * @param level Level to set the image for. + * @param xoffset Left offset of the sub-region to update. + * @param yoffset Bottom offset of the sub-region to update. + * @param zoffset Depth offset of the sub-region to update. + * @param width Width of the sub-region to update. + * @param height Height of the sub-region to update. + * @param depth Depth of the sub-region to update. + * @param buffer Client-side buffer containing the image to set. + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention \p level must be less than getLevels(). + * @attention \p buffer's Texture::Format must match that of getFormat(). + * @attention This Texture instance must use Sampler::SAMPLER_3D, Sampler::SAMPLER_2D_ARRAY + * or Sampler::SAMPLER_CUBEMAP. + * + * @see Builder::sampler() + */ + void setImage(Engine& engine, size_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + uint32_t width, uint32_t height, uint32_t depth, + PixelBufferDescriptor&& buffer) const; + + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { + setImage(engine, level, 0, 0, 0, + uint32_t(getWidth(level)), uint32_t(getHeight(level)), 1, std::move(buffer)); + } + + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + PixelBufferDescriptor&& buffer) const { + setImage(engine, level, xoffset, yoffset, 0, width, height, 1, std::move(buffer)); + } + + /** + * Specify all six images of a cube map level. + * + * This method follows exactly the OpenGL conventions. + * + * @param engine Engine this texture is associated to. + * @param level Level to set the image for. + * @param buffer Client-side buffer containing the images to set. + * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets + * are specified in the following order: +x, -x, +y, -y, +z, -z + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention \p level must be less than getLevels(). + * @attention \p buffer's Texture::Format must match that of getFormat(). + * @attention This Texture instance must use Sampler::SAMPLER_CUBEMAP or it has no effect + * + * @see Texture::CubemapFace, Builder::sampler() + * + * @deprecated Instead, use setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + UTILS_DEPRECATED + void setImage(Engine& engine, size_t level, + PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; + + + /** + * Specify the external image to associate with this Texture. Typically the external + * image is OS specific, and can be a video or camera frame. + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. Supported types are + * eglImageOES on Android and CVPixelBufferRef on iOS. + * + * On iOS the following pixel formats are supported: + * - kCVPixelFormatType_32BGRA + * - kCVPixelFormatType_420YpCbCr8BiPlanarFullRange + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * + * @see Builder::sampler() + * + */ + void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; + + /** + * Specify the external image and plane to associate with this Texture. Typically the external + * image is OS specific, and can be a video or camera frame. When using this method, the + * external image must be a planar type (such as a YUV camera frame). The plane parameter + * selects which image plane is bound to this texture. + * + * A single external image can be bound to different Filament textures, with each texture + * associated with a separate plane: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * textureA->setExternalImage(engine, image, 0); + * textureB->setExternalImage(engine, image, 1); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. Supported types are + * eglImageOES on Android and CVPixelBufferRef on iOS. + * @param plane The plane index of the external image to associate with this texture. + * + * This method is only meaningful on iOS with + * kCVPixelFormatType_420YpCbCr8BiPlanarFullRange images. On platforms + * other than iOS, this method is a no-op. + */ + void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane) noexcept; + + /** + * Specify the external stream to associate with this Texture. Typically the external + * stream is OS specific, and can be a video or camera stream. + * There are many restrictions when using an external stream as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external stream + * + * @param engine Engine this texture is associated to. + * @param stream A Stream object + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * + * @see Builder::sampler(), Stream + * + */ + void setExternalStream(Engine& engine, Stream* UTILS_NULLABLE stream) noexcept; + + /** + * Generates all the mipmap levels automatically. This requires the texture to have a + * color-renderable format and usage set to BLIT_SRC | BLIT_DST. If unspecified, + * usage bits are set automatically. + * + * @param engine Engine this texture is associated to. + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must NOT use SamplerType::SAMPLER_3D or it has no effect + */ + void generateMipmaps(Engine& engine) const noexcept; + + /** + * Creates a reflection map from an environment map. + * + * This is a utility function that replaces calls to Texture::setImage(). + * The provided environment map is processed and all mipmap levels are populated. The + * processing is similar to the offline tool `cmgen` as a lower quality setting. + * + * This function is intended to be used when the environment cannot be processed offline, + * for instance if it's generated at runtime. + * + * The source data must obey to some constraints: + * - the data type must be PixelDataFormat::RGB + * - the data format must be one of + * - PixelDataType::FLOAT + * - PixelDataType::HALF + * + * The current texture must be a cubemap + * + * The reflections cubemap's internal format cannot be a compressed format. + * + * The reflections cubemap's dimension must be a power-of-two. + * + * @warning This operation is computationally intensive, especially with large environments and + * is currently synchronous. Expect about 1ms for a 16x16 cubemap. + * + * @param engine Reference to the filament::Engine to associate this IndirectLight with. + * @param buffer Client-side buffer containing the images to set. + * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets + * are specified in the following order: +x, -x, +y, -y, +z, -z + * @param options Optional parameter to controlling user-specified quality and options. + * + * @exception utils::PreConditionPanic if the source data constraints are not respected. + * + */ + void generatePrefilterMipmap(Engine& engine, + PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, + PrefilterOptions const* UTILS_NULLABLE options = nullptr); + + + /** @deprecated */ + struct FaceOffsets { + using size_type = size_t; + union { + struct { + size_type px; //!< +x face offset in bytes + size_type nx; //!< -x face offset in bytes + size_type py; //!< +y face offset in bytes + size_type ny; //!< -y face offset in bytes + size_type pz; //!< +z face offset in bytes + size_type nz; //!< -z face offset in bytes + }; + size_type offsets[6]; + }; + size_type operator[](size_t n) const noexcept { return offsets[n]; } + size_type& operator[](size_t n) { return offsets[n]; } + FaceOffsets() noexcept = default; + explicit FaceOffsets(size_type faceSize) noexcept { + px = faceSize * 0; + nx = faceSize * 1; + py = faceSize * 2; + ny = faceSize * 3; + pz = faceSize * 4; + nz = faceSize * 5; + } + FaceOffsets(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + } + FaceOffsets& operator=(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + return *this; + } + }; + +protected: + // prevent heap allocation + ~Texture() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TEXTURE_H diff --git a/package/android/libs/filament/include/filament/TextureSampler.h b/package/android/libs/filament/include/filament/TextureSampler.h new file mode 100644 index 00000000..ba5e5534 --- /dev/null +++ b/package/android/libs/filament/include/filament/TextureSampler.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_TEXTURESAMPLER_H +#define TNT_FILAMENT_TEXTURESAMPLER_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * TextureSampler defines how a texture is accessed. + */ +class UTILS_PUBLIC TextureSampler { +public: + using WrapMode = backend::SamplerWrapMode; + using MinFilter = backend::SamplerMinFilter; + using MagFilter = backend::SamplerMagFilter; + using CompareMode = backend::SamplerCompareMode; + using CompareFunc = backend::SamplerCompareFunc; + + /** + * Creates a default sampler. + * The default parameters are: + * - filterMag : NEAREST + * - filterMin : NEAREST + * - wrapS : CLAMP_TO_EDGE + * - wrapT : CLAMP_TO_EDGE + * - wrapR : CLAMP_TO_EDGE + * - compareMode : NONE + * - compareFunc : Less or equal + * - no anisotropic filtering + */ + TextureSampler() noexcept = default; + + explicit TextureSampler(backend::SamplerParams params) noexcept : mSamplerParams(params) { } + + TextureSampler(const TextureSampler& rhs) noexcept = default; + TextureSampler& operator=(const TextureSampler& rhs) noexcept = default; + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param minMag filtering for both minification and magnification + * @param str wrapping mode for all texture coordinate axes + */ + explicit TextureSampler(MagFilter minMag, WrapMode str = WrapMode::CLAMP_TO_EDGE) noexcept { + mSamplerParams.filterMin = MinFilter(minMag); + mSamplerParams.filterMag = minMag; + mSamplerParams.wrapS = str; + mSamplerParams.wrapT = str; + mSamplerParams.wrapR = str; + } + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param min filtering for minification + * @param mag filtering for magnification + * @param str wrapping mode for all texture coordinate axes + */ + TextureSampler(MinFilter min, MagFilter mag, WrapMode str = WrapMode::CLAMP_TO_EDGE) noexcept { + mSamplerParams.filterMin = min; + mSamplerParams.filterMag = mag; + mSamplerParams.wrapS = str; + mSamplerParams.wrapT = str; + mSamplerParams.wrapR = str; + } + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param min filtering for minification + * @param mag filtering for magnification + * @param s wrap mode for the s (horizontal)texture coordinate + * @param t wrap mode for the t (vertical) texture coordinate + * @param r wrap mode for the r (depth) texture coordinate + */ + TextureSampler(MinFilter min, MagFilter mag, WrapMode s, WrapMode t, WrapMode r) noexcept { + mSamplerParams.filterMin = min; + mSamplerParams.filterMag = mag; + mSamplerParams.wrapS = s; + mSamplerParams.wrapT = t; + mSamplerParams.wrapR = r; + } + + /** + * Creates a TextureSampler with the default parameters but setting the compare mode and function + * @param mode Compare mode + * @param func Compare function + */ + explicit TextureSampler(CompareMode mode, CompareFunc func = CompareFunc::LE) noexcept { + mSamplerParams.compareMode = mode; + mSamplerParams.compareFunc = func; + } + + /** + * Sets the minification filter + * @param v Minification filter + */ + void setMinFilter(MinFilter v) noexcept { + mSamplerParams.filterMin = v; + } + + /** + * Sets the magnification filter + * @param v Magnification filter + */ + void setMagFilter(MagFilter v) noexcept { + mSamplerParams.filterMag = v; + } + + /** + * Sets the wrap mode for the s (horizontal) texture coordinate + * @param v wrap mode + */ + void setWrapModeS(WrapMode v) noexcept { + mSamplerParams.wrapS = v; + } + + /** + * Sets the wrap mode for the t (vertical) texture coordinate + * @param v wrap mode + */ + void setWrapModeT(WrapMode v) noexcept { + mSamplerParams.wrapT = v; + } + + /** + * Sets the wrap mode for the r (depth, for 3D textures) texture coordinate + * @param v wrap mode + */ + void setWrapModeR(WrapMode v) noexcept { + mSamplerParams.wrapR = v; + } + + /** + * This controls anisotropic filtering. + * @param anisotropy Amount of anisotropy, should be a power-of-two. The default is 0. + * The maximum permissible value is 7. + */ + void setAnisotropy(float anisotropy) noexcept { + const int log2 = ilogbf(anisotropy > 0 ? anisotropy : -anisotropy); + mSamplerParams.anisotropyLog2 = uint8_t(log2 < 7 ? log2 : 7); + } + + /** + * Sets the compare mode and function. + * @param mode Compare mode + * @param func Compare function + */ + void setCompareMode(CompareMode mode, CompareFunc func = CompareFunc::LE) noexcept { + mSamplerParams.compareMode = mode; + mSamplerParams.compareFunc = func; + } + + //! returns the minification filter value + MinFilter getMinFilter() const noexcept { return mSamplerParams.filterMin; } + + //! returns the magnification filter value + MagFilter getMagFilter() const noexcept { return mSamplerParams.filterMag; } + + //! returns the s-coordinate wrap mode (horizontal) + WrapMode getWrapModeS() const noexcept { return mSamplerParams.wrapS; } + + //! returns the t-coordinate wrap mode (vertical) + WrapMode getWrapModeT() const noexcept { return mSamplerParams.wrapT; } + + //! returns the r-coordinate wrap mode (depth) + WrapMode getWrapModeR() const noexcept { return mSamplerParams.wrapR; } + + //! returns the anisotropy value + float getAnisotropy() const noexcept { return float(1u << mSamplerParams.anisotropyLog2); } + + //! returns the compare mode + CompareMode getCompareMode() const noexcept { return mSamplerParams.compareMode; } + + //! returns the compare function + CompareFunc getCompareFunc() const noexcept { return mSamplerParams.compareFunc; } + + + // no user-serviceable parts below... + backend::SamplerParams getSamplerParams() const noexcept { return mSamplerParams; } + +private: + backend::SamplerParams mSamplerParams{}; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TEXTURESAMPLER_H diff --git a/package/android/libs/filament/include/filament/ToneMapper.h b/package/android/libs/filament/include/filament/ToneMapper.h new file mode 100644 index 00000000..74e26614 --- /dev/null +++ b/package/android/libs/filament/include/filament/ToneMapper.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef TNT_FILAMENT_TONEMAPPER_H +#define TNT_FILAMENT_TONEMAPPER_H + +#include + +#include + +#include + +namespace filament { + +/** + * Interface for tone mapping operators. A tone mapping operator, or tone mapper, + * is responsible for compressing the dynamic range of the rendered scene to a + * dynamic range suitable for display. + * + * In Filament, tone mapping is a color grading step. ToneMapper instances are + * created and passed to the ColorGrading::Builder to produce a 3D LUT that will + * be used during post-processing to prepare the final color buffer for display. + * + * Filament provides several default tone mapping operators that fall into three + * categories: + * + * - Configurable tone mapping operators + * - GenericToneMapper + * - Fixed-aesthetic tone mapping operators + * - ACESToneMapper + * - ACESLegacyToneMapper + * - FilmicToneMapper + * - Debug/validation tone mapping operators + * - LinearToneMapper + * - DisplayRangeToneMapper + * + * You can create custom tone mapping operators by subclassing ToneMapper. + */ +struct UTILS_PUBLIC ToneMapper { + ToneMapper() noexcept; + virtual ~ToneMapper() noexcept; + + /** + * Maps an open domain (or "scene referred" values) color value to display + * domain (or "display referred") color value. Both the input and output + * color values are defined in the Rec.2020 color space, with no transfer + * function applied ("linear Rec.2020"). + * + * @param c Input color to tone map, in the Rec.2020 color space with no + * transfer function applied ("linear") + * + * @return A tone mapped color in the Rec.2020 color space, with no transfer + * function applied ("linear") + */ + virtual math::float3 operator()(math::float3 c) const noexcept = 0; +}; + +/** + * Linear tone mapping operator that returns the input color but clamped to + * the 0..1 range. This operator is mostly useful for debugging. + */ +struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper { + LinearToneMapper() noexcept; + ~LinearToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * ACES tone mapping operator. This operator is an implementation of the + * ACES Reference Rendering Transform (RRT) combined with the Output Device + * Transform (ODT) for sRGB monitors (dim surround, 100 nits). + */ +struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper { + ACESToneMapper() noexcept; + ~ACESToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * ACES tone mapping operator, modified to match the perceived brightness + * of FilmicToneMapper. This operator is the same as ACESToneMapper but + * applies a brightness multiplier of ~1.6 to the input color value to + * target brighter viewing environments. + */ +struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper { + ACESLegacyToneMapper() noexcept; + ~ACESLegacyToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * "Filmic" tone mapping operator. This tone mapper was designed to + * approximate the aesthetics of the ACES RRT + ODT for Rec.709 + * and historically Filament's default tone mapping operator. It exists + * only for backward compatibility purposes and is not otherwise recommended. + */ +struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper { + FilmicToneMapper() noexcept; + ~FilmicToneMapper() noexcept final; + + math::float3 operator()(math::float3 x) const noexcept override; +}; + +/** + * AgX tone mapping operator. + */ +struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper { + + enum class AgxLook : uint8_t { + NONE = 0, //!< Base contrast with no look applied + PUNCHY, //!< A punchy and more chroma laden look for sRGB displays + GOLDEN //!< A golden tinted, slightly washed look for BT.1886 displays + }; + + /** + * Builds a new AgX tone mapper. + * + * @param look an optional creative adjustment to contrast and saturation + */ + explicit AgxToneMapper(AgxLook look = AgxLook::NONE) noexcept; + ~AgxToneMapper() noexcept final; + + math::float3 operator()(math::float3 x) const noexcept override; + + AgxLook look; +}; + +/** + * Generic tone mapping operator that gives control over the tone mapping + * curve. This operator can be used to control the aesthetics of the final + * image. This operator also allows to control the dynamic range of the + * scene referred values. + * + * The tone mapping curve is defined by 5 parameters: + * - contrast: controls the contrast of the curve + * - midGrayIn: sets the input middle gray + * - midGrayOut: sets the output middle gray + * - hdrMax: defines the maximum input value that will be mapped to + * output white + */ +struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper { + /** + * Builds a new generic tone mapper. The default values of the + * constructor parameters approximate an ACES tone mapping curve + * and the maximum input value is set to 10.0. + * + * @param contrast controls the contrast of the curve, must be > 0.0, values + * in the range 0.5..2.0 are recommended. + * @param midGrayIn sets the input middle gray, between 0.0 and 1.0. + * @param midGrayOut sets the output middle gray, between 0.0 and 1.0. + * @param hdrMax defines the maximum input value that will be mapped to + * output white. Must be >= 1.0. + */ + explicit GenericToneMapper( + float contrast = 1.55f, + float midGrayIn = 0.18f, + float midGrayOut = 0.215f, + float hdrMax = 10.0f + ) noexcept; + ~GenericToneMapper() noexcept final; + + GenericToneMapper(GenericToneMapper const&) = delete; + GenericToneMapper& operator=(GenericToneMapper const&) = delete; + GenericToneMapper(GenericToneMapper&& rhs) noexcept; + GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept; + + math::float3 operator()(math::float3 x) const noexcept override; + + /** Returns the contrast of the curve as a strictly positive value. */ + float getContrast() const noexcept; + + /** Returns how fast scene referred values map to output white as a value between 0.0 and 1.0. */ + float getShoulder() const noexcept; + + /** Returns the middle gray point for input values as a value between 0.0 and 1.0. */ + float getMidGrayIn() const noexcept; + + /** Returns the middle gray point for output values as a value between 0.0 and 1.0. */ + float getMidGrayOut() const noexcept; + + /** Returns the maximum input value that will map to output white, as a value >= 1.0. */ + float getHdrMax() const noexcept; + + /** Sets the contrast of the curve, must be > 0.0, values in the range 0.5..2.0 are recommended. */ + void setContrast(float contrast) noexcept; + + /** Sets the input middle gray, between 0.0 and 1.0. */ + void setMidGrayIn(float midGrayIn) noexcept; + + /** Sets the output middle gray, between 0.0 and 1.0. */ + void setMidGrayOut(float midGrayOut) noexcept; + + /** Defines the maximum input value that will be mapped to output white. Must be >= 1.0. */ + void setHdrMax(float hdrMax) noexcept; + +private: + struct Options; + Options* mOptions; +}; + +/** + * A tone mapper that converts the input HDR RGB color into one of 16 debug colors + * that represent the pixel's exposure. When the output is cyan, the input color + * represents middle gray (18% exposure). Every exposure stop above or below middle + * gray causes a color shift. + * + * The relationship between exposures and colors is: + * + * - -5EV black + * - -4EV darkest blue + * - -3EV darker blue + * - -2EV dark blue + * - -1EV blue + * - OEV cyan + * - +1EV dark green + * - +2EV green + * - +3EV yellow + * - +4EV yellow-orange + * - +5EV orange + * - +6EV bright red + * - +7EV red + * - +8EV magenta + * - +9EV purple + * - +10EV white + * + * This tone mapper is useful to validate and tweak scene lighting. + */ +struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper { + DisplayRangeToneMapper() noexcept; + ~DisplayRangeToneMapper() noexcept override; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TONEMAPPER_H diff --git a/package/android/libs/filament/include/filament/TransformManager.h b/package/android/libs/filament/include/filament/TransformManager.h new file mode 100644 index 00000000..5d612a16 --- /dev/null +++ b/package/android/libs/filament/include/filament/TransformManager.h @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_TRANSFORMMANAGER_H +#define TNT_FILAMENT_TRANSFORMMANAGER_H + +#include + +#include +#include + +#include + +#include + +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament { + +class FTransformManager; + +/** + * TransformManager is used to add transform components to entities. + * + * A Transform component gives an entity a position and orientation in space in the coordinate + * space of its parent transform. The TransformManager takes care of computing the world-space + * transform of each component (i.e. its transform relative to the root). + * + * Creation and destruction + * ======================== + * + * A transform component is created using TransformManager::create() and destroyed by calling + * TransformManager::destroy(). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * utils::Entity object = utils::EntityManager.get().create(); + * + * auto& tcm = engine->getTransformManager(); + * + * // create the transform component + * tcm.create(object); + * + * // set its transform + * auto i = tcm.getInstance(object); + * tcm.setTransform(i, mat4f::translation({ 0, 0, -1 })); + * + * // destroy the transform component + * tcm.destroy(object); + * ~~~~~~~~~~~ + * + */ +class UTILS_PUBLIC TransformManager : public FilamentAPI { +public: + using Instance = utils::EntityInstance; + + class children_iterator { + friend class FTransformManager; + TransformManager const& mManager; + Instance mInstance; + children_iterator(TransformManager const& mgr, Instance instance) noexcept + : mManager(mgr), mInstance(instance) { } + public: + using value_type = Instance; + using difference_type = ptrdiff_t; + using pointer = Instance*; + using reference = Instance&; + using iterator_category = std::forward_iterator_tag; + + children_iterator& operator++(); + + children_iterator operator++(int) { // NOLINT + children_iterator ret(*this); + ++(*this); + return ret; + } + + bool operator == (const children_iterator& other) const noexcept { + return mInstance == other.mInstance; + } + + bool operator != (const children_iterator& other) const noexcept { + return mInstance != other.mInstance; + } + + value_type operator*() const { return mInstance; } + }; + + /** + * Returns whether a particular Entity is associated with a component of this TransformManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * Gets an Instance representing the transform component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the transform component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(utils::Entity e) const noexcept; + + /** + * @return the number of Components + */ + size_t getComponentCount() const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * Enables or disable the accurate translation mode. Disabled by default. + * + * When accurate translation mode is active, the translation component of all transforms is + * maintained at double precision. This is only useful if the mat4 version of setTransform() + * is used, as well as getTransformAccurate(). + * + * @param enable true to enable the accurate translation mode, false to disable. + * + * @see isAccurateTranslationsEnabled + * @see create(utils::Entity, Instance, const math::mat4&); + * @see setTransform(Instance, const math::mat4&) + * @see getTransformAccurate + * @see getWorldTransformAccurate + */ + void setAccurateTranslationsEnabled(bool enable) noexcept; + + /** + * Returns whether the high precision translation mode is active. + * @return true if accurate translations mode is active, false otherwise + * @see setAccurateTranslationsEnabled + */ + bool isAccurateTranslationsEnabled() const noexcept; + + /** + * Creates a transform component and associate it with the given entity. + * @param entity An Entity to associate a transform component to. + * @param parent The Instance of the parent transform, or Instance{} if no parent. + * @param localTransform The transform to initialize the transform component with. + * This is always relative to the parent. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(utils::Entity e) was called. + * + * @see destroy() + */ + void create(utils::Entity entity, Instance parent, const math::mat4f& localTransform); + void create(utils::Entity entity, Instance parent, const math::mat4& localTransform); //!< \overload + void create(utils::Entity entity, Instance parent = {}); //!< \overload + + /** + * Destroys this component from the given entity, children are orphaned. + * @param e An entity. + * + * @note If this transform had children, these are orphaned, which means their local + * transform becomes a world transform. Usually it's nonsensical. It's recommended to make + * sure that a destroyed transform doesn't have children. + * + * @see create() + */ + void destroy(utils::Entity e) noexcept; + + /** + * Re-parents an entity to a new one. + * @param i The instance of the transform component to re-parent + * @param newParent The instance of the new parent transform + * @attention It is an error to re-parent an entity to a descendant and will cause undefined behaviour. + * @see getInstance() + */ + void setParent(Instance i, Instance newParent) noexcept; + + /** + * Returns the parent of a transform component, or the null entity if it is a root. + * @param i The instance of the transform component to query. + */ + utils::Entity getParent(Instance i) const noexcept; + + /** + * Returns the number of children of a transform component. + * @param i The instance of the transform component to query. + * @return The number of children of the queried component. + */ + size_t getChildCount(Instance i) const noexcept; + + /** + * Gets a list of children for a transform component. + * + * @param i The instance of the transform component to query. + * @param children Pointer to array-of-Entity. The array must have at least "count" elements. + * @param count The maximum number of children to retrieve. + * @return The number of children written to the pointer. + */ + size_t getChildren(Instance i, utils::Entity* UTILS_NONNULL children, size_t count) const noexcept; + + /** + * Returns an iterator to the Instance of the first child of the given parent. + * + * @param parent Instance of the parent + * @return A forward iterator pointing to the first child of the given parent. + * + * A child_iterator can only safely be dereferenced if it's different from getChildrenEnd(parent) + */ + children_iterator getChildrenBegin(Instance parent) const noexcept; + + /** + * Returns an undreferencable iterator representing the end of the children list + * + * @param parent Instance of the parent + * @return A forward iterator. + * + * This iterator cannot be dereferenced + */ + children_iterator getChildrenEnd(Instance parent) const noexcept; + + /** + * Sets a local transform of a transform component. + * @param ci The instance of the transform component to set the local transform to. + * @param localTransform The local transform (i.e. relative to the parent). + * @see getTransform() + * @attention This operation can be slow if the hierarchy of transform is too deep, and this + * will be particularly bad when updating a lot of transforms. In that case, + * consider using openLocalTransformTransaction() / commitLocalTransformTransaction(). + */ + void setTransform(Instance ci, const math::mat4f& localTransform) noexcept; + + /** + * Sets a local transform of a transform component and keeps double precision translation. + * All other values of the transform are stored at single precision. + * @param ci The instance of the transform component to set the local transform to. + * @param localTransform The local transform (i.e. relative to the parent). + * @see getTransform() + * @attention This operation can be slow if the hierarchy of transform is too deep, and this + * will be particularly bad when updating a lot of transforms. In that case, + * consider using openLocalTransformTransaction() / commitLocalTransformTransaction(). + */ + void setTransform(Instance ci, const math::mat4& localTransform) noexcept; + + /** + * Returns the local transform of a transform component. + * @param ci The instance of the transform component to query the local transform from. + * @return The local transform of the component (i.e. relative to the parent). This always + * returns the value set by setTransform(). + * @see setTransform() + */ + const math::mat4f& getTransform(Instance ci) const noexcept; + + /** + * Returns the local transform of a transform component. + * @param ci The instance of the transform component to query the local transform from. + * @return The local transform of the component (i.e. relative to the parent). This always + * returns the value set by setTransform(). + * @see setTransform() + */ + math::mat4 getTransformAccurate(Instance ci) const noexcept; + + /** + * Return the world transform of a transform component. + * @param ci The instance of the transform component to query the world transform from. + * @return The world transform of the component (i.e. relative to the root). This is the + * composition of this component's local transform with its parent's world transform. + * @see setTransform() + */ + const math::mat4f& getWorldTransform(Instance ci) const noexcept; + + /** + * Return the world transform of a transform component. + * @param ci The instance of the transform component to query the world transform from. + * @return The world transform of the component (i.e. relative to the root). This is the + * composition of this component's local transform with its parent's world transform. + * @see setTransform() + */ + math::mat4 getWorldTransformAccurate(Instance ci) const noexcept; + + /** + * Opens a local transform transaction. During a transaction, getWorldTransform() can + * return an invalid transform until commitLocalTransformTransaction() is called. However, + * setTransform() will perform significantly better and in constant time. + * + * This is useful when updating many transforms and the transform hierarchy is deep (say more + * than 4 or 5 levels). + * + * @note If the local transform transaction is already open, this is a no-op. + * + * @see commitLocalTransformTransaction(), setTransform() + */ + void openLocalTransformTransaction() noexcept; + + /** + * Commits the currently open local transform transaction. When this returns, calls + * to getWorldTransform() will return the proper value. + * + * @attention failing to call this method when done updating the local transform will cause + * a lot of rendering problems. The system never closes the transaction + * automatically. + * + * @note If the local transform transaction is not open, this is a no-op. + * + * @see openLocalTransformTransaction(), setTransform() + */ + void commitLocalTransformTransaction() noexcept; + +protected: + // prevent heap allocation + ~TransformManager() = default; +}; + +} // namespace filament + + +#endif // TNT_TRANSFORMMANAGER_H diff --git a/package/android/libs/filament/include/filament/VertexBuffer.h b/package/android/libs/filament/include/filament/VertexBuffer.h new file mode 100644 index 00000000..fccbd004 --- /dev/null +++ b/package/android/libs/filament/include/filament/VertexBuffer.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VERTEXBUFFER_H +#define TNT_FILAMENT_VERTEXBUFFER_H + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FVertexBuffer; + +class BufferObject; +class Engine; + +/** + * Holds a set of buffers that define the geometry of a Renderable. + * + * The geometry of the Renderable itself is defined by a set of vertex attributes such as + * position, color, normals, tangents, etc... + * + * There is no need to have a 1-to-1 mapping between attributes and buffer. A buffer can hold the + * data of several attributes -- attributes are then referred as being "interleaved". + * + * The buffers themselves are GPU resources, therefore mutating their data can be relatively slow. + * For this reason, it is best to separate the constant data from the dynamic data into multiple + * buffers. + * + * It is possible, and even encouraged, to use a single vertex buffer for several Renderables. + * + * @see IndexBuffer, RenderableManager + */ +class UTILS_PUBLIC VertexBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + using AttributeType = backend::ElementType; + using BufferDescriptor = backend::BufferDescriptor; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Defines how many buffers will be created in this vertex buffer set. These buffers are + * later referenced by index from 0 to \p bufferCount - 1. + * + * This call is mandatory. The default is 0. + * + * @param bufferCount Number of buffers in this vertex buffer set. The maximum value is 8. + * @return A reference to this Builder for chaining calls. + */ + Builder& bufferCount(uint8_t bufferCount) noexcept; + + /** + * Size of each buffer in the set in vertex. + * + * @param vertexCount Number of vertices in each buffer in this set. + * @return A reference to this Builder for chaining calls. + */ + Builder& vertexCount(uint32_t vertexCount) noexcept; + + /** + * Allows buffers to be swapped out and shared using BufferObject. + * + * If buffer objects mode is enabled, clients must call setBufferObjectAt rather than + * setBufferAt. This allows sharing of data between VertexBuffer objects, but it may + * slightly increase the memory footprint of Filament's internal bookkeeping. + * + * @param enabled If true, enables buffer object mode. False by default. + */ + Builder& enableBufferObjects(bool enabled = true) noexcept; + + /** + * Sets up an attribute for this vertex buffer set. + * + * Using \p byteOffset and \p byteStride, attributes can be interleaved in the same buffer. + * + * @param attribute The attribute to set up. + * @param bufferIndex The index of the buffer containing the data for this attribute. Must + * be between 0 and bufferCount() - 1. + * @param attributeType The type of the attribute data (e.g. byte, float3, etc...) + * @param byteOffset Offset in *bytes* into the buffer \p bufferIndex + * @param byteStride Stride in *bytes* to the next element of this attribute. When set to + * zero the attribute size, as defined by \p attributeType is used. + * + * @return A reference to this Builder for chaining calls. + * + * @warning VertexAttribute::TANGENTS must be specified as a quaternion and is how normals + * are specified. + * + * @warning Not all backends support 3-component attributes that are not floats. For help + * with conversion, see geometry::Transcoder. + * + * @see VertexAttribute + * + * This is a no-op if the \p attribute is an invalid enum. + * This is a no-op if the \p bufferIndex is out of bounds. + * + */ + Builder& attribute(VertexAttribute attribute, uint8_t bufferIndex, + AttributeType attributeType, + uint32_t byteOffset = 0, uint8_t byteStride = 0) noexcept; + + /** + * Sets whether a given attribute should be normalized. By default attributes are not + * normalized. A normalized attribute is mapped between 0 and 1 in the shader. This applies + * only to integer types. + * + * @param attribute Enum of the attribute to set the normalization flag to. + * @param normalize true to automatically normalize the given attribute. + * @return A reference to this Builder for chaining calls. + * + * This is a no-op if the \p attribute is an invalid enum. + */ + Builder& normalized(VertexAttribute attribute, bool normalize = true) noexcept; + + /** + * Sets advanced skinning mode. Bone data, indices and weights will be + * set in RenderableManager:Builder:boneIndicesAndWeights methods. + * Works with or without buffer objects. + * + * @param enabled If true, enables advanced skinning mode. False by default. + * + * @return A reference to this Builder for chaining calls. + * + * @see RenderableManager:Builder:boneIndicesAndWeights + */ + Builder& advancedSkinning(bool enabled) noexcept; + + /** + * Creates the VertexBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + VertexBuffer* UTILS_NONNULL build(Engine& engine); + + private: + friend class FVertexBuffer; + }; + + /** + * Returns the vertex count. + * @return Number of vertices in this vertex buffer set. + */ + size_t getVertexCount() const noexcept; + + /** + * Asynchronously copy-initializes the specified buffer from the given buffer data. + * + * Do not use this if you called enableBufferObjects() on the Builder. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * @param bufferIndex Index of the buffer to initialize. Must be between 0 + * and Builder::bufferCount() - 1. + * @param buffer A BufferDescriptor representing the data used to initialize the buffer at + * index \p bufferIndex. BufferDescriptor points to raw, untyped data that will + * be copied as-is into the buffer. + * @param byteOffset Offset in *bytes* into the buffer at index \p bufferIndex of this vertex + * buffer set. + */ + void setBufferAt(Engine& engine, uint8_t bufferIndex, BufferDescriptor&& buffer, + uint32_t byteOffset = 0); + + /** + * Swaps in the given buffer object. + * + * To use this, you must first call enableBufferObjects() on the Builder. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * @param bufferIndex Index of the buffer to initialize. Must be between 0 + * and Builder::bufferCount() - 1. + * @param bufferObject The handle to the GPU data that will be used in this buffer slot. + */ + void setBufferObjectAt(Engine& engine, uint8_t bufferIndex, + BufferObject const* UTILS_NONNULL bufferObject); + +protected: + // prevent heap allocation + ~VertexBuffer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VERTEXBUFFER_H diff --git a/package/android/libs/filament/include/filament/View.h b/package/android/libs/filament/include/filament/View.h new file mode 100644 index 00000000..3cdd527f --- /dev/null +++ b/package/android/libs/filament/include/filament/View.h @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VIEW_H +#define TNT_FILAMENT_VIEW_H + +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +namespace backend { +class CallbackHandler; +} // namespace backend + +class Camera; +class ColorGrading; +class MaterialInstance; +class RenderTarget; +class Scene; +class Viewport; + +/** + * A View encompasses all the state needed for rendering a Scene. + * + * Renderer::render() operates on View objects. These View objects specify important parameters + * such as: + * - The Scene + * - The Camera + * - The Viewport + * - Some rendering parameters + * + * \note + * View instances are heavy objects that internally cache a lot of data needed for rendering. + * It is not advised for an application to use many View objects. + * + * For example, in a game, a View could be used for the main scene and another one for the + * game's user interface. More View instances could be used for creating special effects (e.g. + * a View is akin to a rendering pass). + * + * + * @see Renderer, Scene, Camera, RenderTarget + */ +class UTILS_PUBLIC View : public FilamentAPI { +public: + using QualityLevel = filament::QualityLevel; + using BlendMode = filament::BlendMode; + using AntiAliasing = filament::AntiAliasing; + using Dithering = filament::Dithering; + using ShadowType = filament::ShadowType; + + using DynamicResolutionOptions = filament::DynamicResolutionOptions; + using BloomOptions = filament::BloomOptions; + using FogOptions = filament::FogOptions; + using DepthOfFieldOptions = filament::DepthOfFieldOptions; + using VignetteOptions = filament::VignetteOptions; + using RenderQuality = filament::RenderQuality; + using AmbientOcclusionOptions = filament::AmbientOcclusionOptions; + using TemporalAntiAliasingOptions = filament::TemporalAntiAliasingOptions; + using MultiSampleAntiAliasingOptions = filament::MultiSampleAntiAliasingOptions; + using VsmShadowOptions = filament::VsmShadowOptions; + using SoftShadowOptions = filament::SoftShadowOptions; + using ScreenSpaceReflectionsOptions = filament::ScreenSpaceReflectionsOptions; + using GuardBandOptions = filament::GuardBandOptions; + using StereoscopicOptions = filament::StereoscopicOptions; + + /** + * Sets the View's name. Only useful for debugging. + * @param name Pointer to the View's name. The string is copied. + */ + void setName(const char* UTILS_NONNULL name) noexcept; + + /** + * Returns the View's name + * + * @return a pointer owned by the View instance to the View's name. + * + * @attention Do *not* free the pointer or modify its content. + */ + const char* UTILS_NULLABLE getName() const noexcept; + + /** + * Set this View instance's Scene. + * + * @param scene Associate the specified Scene to this View. A Scene can be associated to + * several View instances.\n + * \p scene can be nullptr to dissociate the currently set Scene + * from this View.\n + * The View doesn't take ownership of the Scene pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a Scene from all Views before destroying it. + */ + void setScene(Scene* UTILS_NULLABLE scene); + + /** + * Returns the Scene currently associated with this View. + * @return A pointer to the Scene associated to this View. nullptr if no Scene is set. + */ + Scene* UTILS_NULLABLE getScene() noexcept; + + /** + * Returns the Scene currently associated with this View. + * @return A pointer to the Scene associated to this View. nullptr if no Scene is set. + */ + Scene const* UTILS_NULLABLE getScene() const noexcept { + return const_cast(this)->getScene(); + } + + /** + * Specifies an offscreen render target to render into. + * + * By default, the view's associated render target is nullptr, which corresponds to the + * SwapChain associated with the engine. + * + * A view with a custom render target cannot rely on Renderer::ClearOptions, which only apply + * to the SwapChain. Such view can use a Skybox instead. + * + * @param renderTarget Render target associated with view, or nullptr for the swap chain. + */ + void setRenderTarget(RenderTarget* UTILS_NULLABLE renderTarget) noexcept; + + /** + * Gets the offscreen render target associated with this view. + * + * Returns nullptr if the render target is the swap chain (which is default). + * + * @see setRenderTarget + */ + RenderTarget* UTILS_NULLABLE getRenderTarget() const noexcept; + + /** + * Sets the rectangular region to render to. + * + * The viewport specifies where the content of the View (i.e. the Scene) is rendered in + * the render target. The Render target is automatically clipped to the Viewport. + * + * @param viewport The Viewport to render the Scene into. The Viewport is a value-type, it is + * therefore copied. The parameter can be discarded after this call returns. + */ + void setViewport(Viewport const& viewport) noexcept; + + /** + * Returns the rectangular region that gets rendered to. + * @return A constant reference to View's viewport. + */ + Viewport const& getViewport() const noexcept; + + /** + * Sets this View's Camera. + * + * @param camera Associate the specified Camera to this View. A Camera can be associated to + * several View instances.\n + * \p camera can be nullptr to dissociate the currently set Camera from this + * View.\n + * The View doesn't take ownership of the Camera pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a Camera from all Views before destroying it. + */ + void setCamera(Camera* UTILS_NONNULL camera) noexcept; + + /** + * Returns the Camera currently associated with this View. + * @return A reference to the Camera associated to this View. + */ + Camera& getCamera() noexcept; + + /** + * Returns the Camera currently associated with this View. + * @return A reference to the Camera associated to this View. + */ + Camera const& getCamera() const noexcept { + return const_cast(this)->getCamera(); + } + + /** + * Sets the blending mode used to draw the view into the SwapChain. + * + * @param blendMode either BlendMode::OPAQUE or BlendMode::TRANSLUCENT + * @see getBlendMode + */ + void setBlendMode(BlendMode blendMode) noexcept; + + /** + * + * @return blending mode set by setBlendMode + * @see setBlendMode + */ + BlendMode getBlendMode() const noexcept; + + /** + * Sets which layers are visible. + * + * Renderable objects can have one or several layers associated to them. Layers are + * represented with an 8-bits bitmask, where each bit corresponds to a layer. + * + * This call sets which of those layers are visible. Renderables in invisible layers won't be + * rendered. + * + * @param select a bitmask specifying which layer to set or clear using \p values. + * @param values a bitmask where each bit sets the visibility of the corresponding layer + * (1: visible, 0: invisible), only layers in \p select are affected. + * + * @see RenderableManager::setLayerMask(). + * + * @note By default only layer 0 (bitmask 0x01) is visible. + * @note This is a convenient way to quickly show or hide sets of Renderable objects. + */ + void setVisibleLayers(uint8_t select, uint8_t values) noexcept; + + /** + * Helper function to enable or disable a visibility layer. + * @param layer layer between 0 and 7 to enable or disable + * @param enabled true to enable the layer, false to disable it + * @see RenderableManager::setVisibleLayers() + */ + inline void setLayerEnabled(size_t layer, bool enabled) noexcept { + const uint8_t mask = 1u << layer; + setVisibleLayers(mask, enabled ? mask : 0); + } + + /** + * Get the visible layers. + * + * @see View::setVisibleLayers() + */ + uint8_t getVisibleLayers() const noexcept; + + /** + * Enables or disables shadow mapping. Enabled by default. + * + * @param enabled true enables shadow mapping, false disables it. + * + * @see LightManager::Builder::castShadows(), + * RenderableManager::Builder::receiveShadows(), + * RenderableManager::Builder::castShadows(), + */ + void setShadowingEnabled(bool enabled) noexcept; + + /** + * @return whether shadowing is enabled + */ + bool isShadowingEnabled() const noexcept; + + /** + * Enables or disables screen space refraction. Enabled by default. + * + * @param enabled true enables screen space refraction, false disables it. + */ + void setScreenSpaceRefractionEnabled(bool enabled) noexcept; + + /** + * @return whether screen space refraction is enabled + */ + bool isScreenSpaceRefractionEnabled() const noexcept; + + /** + * Sets how many samples are to be used for MSAA in the post-process stage. + * Default is 1 and disables MSAA. + * + * @param count 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. + * + * @note Anti-aliasing can also be performed in the post-processing stage, generally at lower + * cost. See setAntialiasing. + * + * @see setAntialiasing + * @deprecated use setMultiSampleAntiAliasingOptions instead + */ + UTILS_DEPRECATED + void setSampleCount(uint8_t count = 1) noexcept; + + /** + * Returns the sample count set by setSampleCount(). Effective sample count could be different. + * A value of 0 or 1 means MSAA is disabled. + * + * @return value set by setSampleCount(). + * @deprecated use getMultiSampleAntiAliasingOptions instead + */ + UTILS_DEPRECATED + uint8_t getSampleCount() const noexcept; + + /** + * Enables or disables anti-aliasing in the post-processing stage. Enabled by default. + * MSAA can be enabled in addition, see setSampleCount(). + * + * @param type FXAA for enabling, NONE for disabling anti-aliasing. + * + * @note For MSAA anti-aliasing, see setSamplerCount(). + * + * @see setSampleCount + */ + void setAntiAliasing(AntiAliasing type) noexcept; + + /** + * Queries whether anti-aliasing is enabled during the post-processing stage. To query + * whether MSAA is enabled, see getSampleCount(). + * + * @return The post-processing anti-aliasing method. + */ + AntiAliasing getAntiAliasing() const noexcept; + + /** + * Enables or disable temporal anti-aliasing (TAA). Disabled by default. + * + * @param options temporal anti-aliasing options + */ + void setTemporalAntiAliasingOptions(TemporalAntiAliasingOptions options) noexcept; + + /** + * Returns temporal anti-aliasing options. + * + * @return temporal anti-aliasing options + */ + TemporalAntiAliasingOptions const& getTemporalAntiAliasingOptions() const noexcept; + + /** + * Enables or disable screen-space reflections. Disabled by default. + * + * @param options screen-space reflections options + */ + void setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions options) noexcept; + + /** + * Returns screen-space reflections options. + * + * @return screen-space reflections options + */ + ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept; + + /** + * Enables or disable screen-space guard band. Disabled by default. + * + * @param options guard band options + */ + void setGuardBandOptions(GuardBandOptions options) noexcept; + + /** + * Returns screen-space guard band options. + * + * @return guard band options + */ + GuardBandOptions const& getGuardBandOptions() const noexcept; + + /** + * Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default. + * + * @param options multi-sample anti-aliasing options + */ + void setMultiSampleAntiAliasingOptions(MultiSampleAntiAliasingOptions options) noexcept; + + /** + * Returns multi-sample anti-aliasing options. + * + * @return multi-sample anti-aliasing options + */ + MultiSampleAntiAliasingOptions const& getMultiSampleAntiAliasingOptions() const noexcept; + + /** + * Sets this View's color grading transforms. + * + * @param colorGrading Associate the specified ColorGrading to this View. A ColorGrading can be + * associated to several View instances.\n + * \p colorGrading can be nullptr to dissociate the currently set + * ColorGrading from this View. Doing so will revert to the use of the + * default color grading transforms.\n + * The View doesn't take ownership of the ColorGrading pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a ColorGrading from all Views before destroying it. + */ + void setColorGrading(ColorGrading* UTILS_NULLABLE colorGrading) noexcept; + + /** + * Returns the color grading transforms currently associated to this view. + * @return A pointer to the ColorGrading associated to this View. + */ + const ColorGrading* UTILS_NULLABLE getColorGrading() const noexcept; + + /** + * Sets ambient occlusion options. + * + * @param options Options for ambient occlusion. + */ + void setAmbientOcclusionOptions(AmbientOcclusionOptions const& options) noexcept; + + /** + * Gets the ambient occlusion options. + * + * @return ambient occlusion options currently set. + */ + AmbientOcclusionOptions const& getAmbientOcclusionOptions() const noexcept; + + /** + * Enables or disables bloom in the post-processing stage. Disabled by default. + * + * @param options options + */ + void setBloomOptions(BloomOptions options) noexcept; + + /** + * Queries the bloom options. + * + * @return the current bloom options for this view. + */ + BloomOptions getBloomOptions() const noexcept; + + /** + * Enables or disables fog. Disabled by default. + * + * @param options options + */ + void setFogOptions(FogOptions options) noexcept; + + /** + * Queries the fog options. + * + * @return the current fog options for this view. + */ + FogOptions getFogOptions() const noexcept; + + /** + * Enables or disables Depth of Field. Disabled by default. + * + * @param options options + */ + void setDepthOfFieldOptions(DepthOfFieldOptions options) noexcept; + + /** + * Queries the depth of field options. + * + * @return the current depth of field options for this view. + */ + DepthOfFieldOptions getDepthOfFieldOptions() const noexcept; + + /** + * Enables or disables the vignetted effect in the post-processing stage. Disabled by default. + * + * @param options options + */ + void setVignetteOptions(VignetteOptions options) noexcept; + + /** + * Queries the vignette options. + * + * @return the current vignette options for this view. + */ + VignetteOptions getVignetteOptions() const noexcept; + + /** + * Enables or disables dithering in the post-processing stage. Enabled by default. + * + * @param dithering dithering type + */ + void setDithering(Dithering dithering) noexcept; + + /** + * Queries whether dithering is enabled during the post-processing stage. + * + * @return the current dithering type for this view. + */ + Dithering getDithering() const noexcept; + + /** + * Sets the dynamic resolution options for this view. Dynamic resolution options + * controls whether dynamic resolution is enabled, and if it is, how it behaves. + * + * @param options The dynamic resolution options to use on this view + */ + void setDynamicResolutionOptions(DynamicResolutionOptions const& options) noexcept; + + /** + * Returns the dynamic resolution options associated with this view. + * @return value set by setDynamicResolutionOptions(). + */ + DynamicResolutionOptions getDynamicResolutionOptions() const noexcept; + + /** + * Sets the rendering quality for this view. Refer to RenderQuality for more + * information about the different settings available. + * + * @param renderQuality The render quality to use on this view + */ + void setRenderQuality(RenderQuality const& renderQuality) noexcept; + + /** + * Returns the render quality used by this view. + * @return value set by setRenderQuality(). + */ + RenderQuality getRenderQuality() const noexcept; + + /** + * Sets options relative to dynamic lighting for this view. + * + * @param zLightNear Distance from the camera where the lights are expected to shine. + * This parameter can affect performance and is useful because depending + * on the scene, lights that shine close to the camera may not be + * visible -- in this case, using a larger value can improve performance. + * e.g. when standing and looking straight, several meters of the ground + * isn't visible and if lights are expected to shine there, there is no + * point using a short zLightNear. (Default 5m). + * + * @param zLightFar Distance from the camera after which lights are not expected to be visible. + * Similarly to zLightNear, setting this value properly can improve + * performance. (Default 100m). + * + * + * Together zLightNear and zLightFar must be chosen so that the visible influence of lights + * is spread between these two values. + * + */ + void setDynamicLightingOptions(float zLightNear, float zLightFar) noexcept; + + /* + * Set the shadow mapping technique this View uses. + * + * The ShadowType affects all the shadows seen within the View. + * + * ShadowType::VSM imposes a restriction on marking renderables as only shadow receivers (but + * not casters). To ensure correct shadowing with VSM, all shadow participant renderables should + * be marked as both receivers and casters. Objects that are guaranteed to not cast shadows on + * themselves or other objects (such as flat ground planes) can be set to not cast shadows, + * which might improve shadow quality. + * + * @warning This API is still experimental and subject to change. + */ + void setShadowType(ShadowType shadow) noexcept; + + /** + * Sets VSM shadowing options that apply across the entire View. + * + * Additional light-specific VSM options can be set with LightManager::setShadowOptions. + * + * Only applicable when shadow type is set to ShadowType::VSM. + * + * @param options Options for shadowing. + * + * @see setShadowType + * + * @warning This API is still experimental and subject to change. + */ + void setVsmShadowOptions(VsmShadowOptions const& options) noexcept; + + /** + * Returns the VSM shadowing options associated with this View. + * + * @return value set by setVsmShadowOptions(). + */ + VsmShadowOptions getVsmShadowOptions() const noexcept; + + /** + * Sets soft shadowing options that apply across the entire View. + * + * Additional light-specific soft shadow parameters can be set with LightManager::setShadowOptions. + * + * Only applicable when shadow type is set to ShadowType::DPCF or ShadowType::PCSS. + * + * @param options Options for shadowing. + * + * @see setShadowType + * + * @warning This API is still experimental and subject to change. + */ + void setSoftShadowOptions(SoftShadowOptions const& options) noexcept; + + /** + * Returns the soft shadowing options associated with this View. + * + * @return value set by setSoftShadowOptions(). + */ + SoftShadowOptions getSoftShadowOptions() const noexcept; + + /** + * Enables or disables post processing. Enabled by default. + * + * Post-processing includes: + * - Depth-of-field + * - Bloom + * - Vignetting + * - Temporal Anti-aliasing (TAA) + * - Color grading & gamma encoding + * - Dithering + * - FXAA + * - Dynamic scaling + * + * Disabling post-processing forgoes color correctness as well as some anti-aliasing techniques + * and should only be used for debugging, UI overlays or when using custom render targets + * (see RenderTarget). + * + * @param enabled true enables post processing, false disables it. + * + * @see setBloomOptions, setColorGrading, setAntiAliasing, setDithering, setSampleCount + */ + void setPostProcessingEnabled(bool enabled) noexcept; + + //! Returns true if post-processing is enabled. See setPostProcessingEnabled() for more info. + bool isPostProcessingEnabled() const noexcept; + + /** + * Inverts the winding order of front faces. By default front faces use a counter-clockwise + * winding order. When the winding order is inverted, front faces are faces with a clockwise + * winding order. + * + * Changing the winding order will directly affect the culling mode in materials + * (see Material::getCullingMode()). + * + * Inverting the winding order of front faces is useful when rendering mirrored reflections + * (water, mirror surfaces, front camera in AR, etc.). + * + * @param inverted True to invert front faces, false otherwise. + */ + void setFrontFaceWindingInverted(bool inverted) noexcept; + + /** + * Returns true if the winding order of front faces is inverted. + * See setFrontFaceWindingInverted() for more information. + */ + bool isFrontFaceWindingInverted() const noexcept; + + /** + * Enables use of the stencil buffer. + * + * The stencil buffer is an 8-bit, per-fragment unsigned integer stored alongside the depth + * buffer. The stencil buffer is cleared at the beginning of a frame and discarded after the + * color pass. + * + * Each fragment's stencil value is set during rasterization by specifying stencil operations on + * a Material. The stencil buffer can be used as a mask for later rendering by setting a + * Material's stencil comparison function and reference value. Fragments that don't pass the + * stencil test are then discarded. + * + * If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER + * flag set in order to use the stencil buffer. + * + * A renderable's priority (see RenderableManager::setPriority) is useful to control the order + * in which primitives are drawn. + * + * @param enabled True to enable the stencil buffer, false disables it (default) + */ + void setStencilBufferEnabled(bool enabled) noexcept; + + /** + * Returns true if the stencil buffer is enabled. + * See setStencilBufferEnabled() for more information. + */ + bool isStencilBufferEnabled() const noexcept; + + /** + * Sets the stereoscopic rendering options for this view. + * + * Currently, only one type of stereoscopic rendering is supported: side-by-side. + * Side-by-side stereo rendering splits the viewport into two halves: a left and right half. + * Eye 0 will render to the left half, while Eye 1 will render into the right half. + * + * Currently, the following features are not supported with stereoscopic rendering: + * - post-processing + * - shadowing + * - punctual lights + * + * Stereo rendering depends on device and platform support. To check if stereo rendering is + * supported, use Engine::isStereoSupported(). If stereo rendering is not supported, then the + * stereoscopic options have no effect. + * + * @param options The stereoscopic options to use on this view + */ + void setStereoscopicOptions(StereoscopicOptions const& options) noexcept; + + /** + * Returns the stereoscopic options associated with this View. + * + * @return value set by setStereoscopicOptions(). + */ + StereoscopicOptions const& getStereoscopicOptions() const noexcept; + + // for debugging... + + //! debugging: allows to entirely disable frustum culling. (culling enabled by default). + void setFrustumCullingEnabled(bool culling) noexcept; + + //! debugging: returns whether frustum culling is enabled. + bool isFrustumCullingEnabled() const noexcept; + + //! debugging: sets the Camera used for rendering. It may be different from the culling camera. + void setDebugCamera(Camera* UTILS_NULLABLE camera) noexcept; + + //! debugging: returns a Camera from the point of view of *the* dominant directional light used for shadowing. + Camera const* UTILS_NULLABLE getDirectionalShadowCamera() const noexcept; + + + /** Result of a picking query */ + struct PickingQueryResult { + utils::Entity renderable{}; //! RenderableManager Entity at the queried coordinates + float depth{}; //! Depth buffer value (1 (near plane) to 0 (infinity)) + uint32_t reserved1{}; + uint32_t reserved2{}; + /** + * screen space coordinates in GL convention, this can be used to compute the view or + * world space position of the picking hit. For e.g.: + * clip_space_position = (fragCoords.xy / viewport.wh, fragCoords.z) * 2.0 - 1.0 + * view_space_position = inverse(projection) * clip_space_position + * world_space_position = model * view_space_position + * + * The viewport, projection and model matrices can be obtained from Camera. Because + * pick() has some latency, it might be more accurate to obtain these values at the + * time the View::pick() call is made. + * + * Note: if the Engine is running at FEATURE_LEVEL_0, the precision or `depth` and + * `fragCoords.z` is only 8-bits. + */ + math::float3 fragCoords; //! screen space coordinates in GL convention + }; + + /** User data for PickingQueryResultCallback */ + struct PickingQuery { + // note: this is enough to store a std::function<> -- just saying... + void* UTILS_NULLABLE storage[4]; + }; + + /** callback type used for picking queries. */ + using PickingQueryResultCallback = + void(*)(PickingQueryResult const& result, PickingQuery* UTILS_NONNULL pq); + + /** + * Helper for creating a picking query from Foo::method, by pointer. + * e.g.: pick(x, y, &foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param instance A pointer to an instance of T + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T* UTILS_NONNULL instance, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + (static_cast(pq->storage[0])->*method)(result); + }, handler); + query.storage[0] = instance; + } + + /** + * Helper for creating a picking query from Foo::method, by copy for a small object + * e.g.: pick(x, y, foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param instance An instance of T + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T instance, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + static_assert(sizeof(instance) <= sizeof(PickingQuery::storage), "user data too large"); + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + T* const that = static_cast(reinterpret_cast(pq->storage)); + (that->*method)(result); + that->~T(); + }, handler); + new(query.storage) T(std::move(instance)); + } + + /** + * Helper for creating a picking query from a small functor + * e.g.: pick(x, y, [](PickingQueryResult const& result){}); + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param functor A functor, typically a lambda function. + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T functor, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + static_assert(sizeof(functor) <= sizeof(PickingQuery::storage), "functor too large"); + PickingQuery& query = pick(x, y, handler, + (PickingQueryResultCallback)[](PickingQueryResult const& result, PickingQuery* pq) { + T* const that = static_cast(reinterpret_cast(pq->storage)); + that->operator()(result); + that->~T(); + }); + new(query.storage) T(std::move(functor)); + } + + /** + * Creates a picking query. Multiple queries can be created (e.g.: multi-touch). + * Picking queries are all executed when Renderer::render() is called on this View. + * The provided callback is guaranteed to be called at some point in the future. + * + * Typically it takes a couple frames to receive the result of a picking query. + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param callback User callback, called when the picking query result is available. + * @param handler Handler to dispatch the callback or nullptr for the default handler. + * @return A reference to a PickingQuery structure, which can be used to store up to + * 8*sizeof(void*) bytes of user data. This user data is later accessible + * in the PickingQueryResultCallback callback 3rd parameter. + */ + PickingQuery& pick(uint32_t x, uint32_t y, + backend::CallbackHandler* UTILS_NULLABLE handler, + PickingQueryResultCallback UTILS_NONNULL callback) noexcept; + + /** + * Set the value of material global variables. There are up-to four such variable each of + * type float4. These variables can be read in a user Material with + * `getMaterialGlobal{0|1|2|3}()`. All variable start with a default value of { 0, 0, 0, 1 } + * + * @param index index of the variable to set between 0 and 3. + * @param value new value for the variable. + * @see getMaterialGlobal + */ + void setMaterialGlobal(uint32_t index, math::float4 const& value); + + /** + * Get the value of the material global variables. + * All variable start with a default value of { 0, 0, 0, 1 } + * + * @param index index of the variable to set between 0 and 3. + * @return current value of the variable. + * @see setMaterialGlobal + */ + math::float4 getMaterialGlobal(uint32_t index) const; + + /** + * Get an Entity representing the large scale fog object. + * This entity is always inherited by the View's Scene. + * + * It is for example possible to create a TransformManager component with this + * Entity and apply a transformation globally on the fog. + * + * @return an Entity representing the large scale fog object. + */ + utils::Entity getFogEntity() const noexcept; + + /** + * List of available ambient occlusion techniques + * @deprecated use AmbientOcclusionOptions::enabled instead + */ + enum class UTILS_DEPRECATED AmbientOcclusion : uint8_t { + NONE = 0, //!< No Ambient Occlusion + SSAO = 1 //!< Basic, sampling SSAO + }; + + /** + * Activates or deactivates ambient occlusion. + * @deprecated use setAmbientOcclusionOptions() instead + * @see setAmbientOcclusionOptions + * + * @param ambientOcclusion Type of ambient occlusion to use. + */ + UTILS_DEPRECATED + void setAmbientOcclusion(AmbientOcclusion ambientOcclusion) noexcept; + + /** + * Queries the type of ambient occlusion active for this View. + * @deprecated use getAmbientOcclusionOptions() instead + * @see getAmbientOcclusionOptions + * + * @return ambient occlusion type. + */ + UTILS_DEPRECATED + AmbientOcclusion getAmbientOcclusion() const noexcept; + +protected: + // prevent heap allocation + ~View() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VIEW_H diff --git a/package/android/libs/filament/include/filament/Viewport.h b/package/android/libs/filament/include/filament/Viewport.h new file mode 100644 index 00000000..29916f70 --- /dev/null +++ b/package/android/libs/filament/include/filament/Viewport.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VIEWPORT_H +#define TNT_FILAMENT_VIEWPORT_H + +#include + +#include + +#include +#include + +namespace filament { + +/** + * Viewport describes a view port in pixel coordinates + * + * A view port is represented by its left-bottom coordinate, width and height in pixels. + */ +class UTILS_PUBLIC Viewport : public backend::Viewport { +public: + /** + * Creates a Viewport of zero width and height at the origin. + */ + Viewport() noexcept : backend::Viewport{} {} + + /** + * Creates a Viewport from its left-bottom coordinates, width and height in pixels + * + * @param left left coordinate in pixel + * @param bottom bottom coordinate in pixel + * @param width width in pixel + * @param height height in pixel + */ + Viewport(int32_t left, int32_t bottom, uint32_t width, uint32_t height) noexcept + : backend::Viewport{ left, bottom, width, height } { + } + + /** + * Returns whether the area of the view port is null. + * + * @return true if either width or height is 0 pixel. + */ + bool empty() const noexcept { return !width || !height; } + +private: + /** + * Compares two Viewports for equality + * @param lhs reference to the left hand side Viewport + * @param rhs reference to the right hand side Viewport + * @return true if \p rhs and \p lhs are identical. + */ + friend bool operator==(Viewport const& lhs, Viewport const& rhs) noexcept { + return (&rhs == &lhs) || + (rhs.left == lhs.left && rhs.bottom == lhs.bottom && + rhs.width == lhs.width && rhs.height == lhs.height); + } + + /** + * Compares two Viewports for inequality + * @param lhs reference to the left hand side Viewport + * @param rhs reference to the right hand side Viewport + * @return true if \p rhs and \p lhs are different. + */ + friend bool operator!=(Viewport const& lhs, Viewport const& rhs) noexcept { + return !(rhs == lhs); + } +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VIEWPORT_H diff --git a/package/android/libs/filament/include/filameshio/MeshReader.h b/package/android/libs/filament/include/filameshio/MeshReader.h new file mode 100644 index 00000000..22533791 --- /dev/null +++ b/package/android/libs/filament/include/filameshio/MeshReader.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_FILAMENT_FILAMESHIO_MESHREADER_H +#define TNT_FILAMENT_FILAMESHIO_MESHREADER_H + +#include +#include +#include + +namespace filament { + class Engine; + class VertexBuffer; + class IndexBuffer; + class MaterialInstance; +} + +namespace utils { + class Path; +} + +namespace filamesh { + + +/** + * This API can be used to read meshes stored in the "filamesh" format produced + * by the command line tool of the same name. This file format is documented in + * "docs/filamesh.md" in the Filament distribution. + */ +class UTILS_PUBLIC MeshReader { +public: + using Callback = void(*)(void* buffer, size_t size, void* user); + + // Class to track material instances + class MaterialRegistry { + public: + MaterialRegistry(); + MaterialRegistry(const MaterialRegistry& rhs); + MaterialRegistry& operator=(const MaterialRegistry& rhs); + ~MaterialRegistry(); + MaterialRegistry(MaterialRegistry&&); + MaterialRegistry& operator=(MaterialRegistry&&); + + filament::MaterialInstance* getMaterialInstance(const utils::CString& name); + + void registerMaterialInstance(const utils::CString& name, + filament::MaterialInstance* materialInstance); + + void unregisterMaterialInstance(const utils::CString& name); + + void unregisterAll(); + + size_t numRegistered() const noexcept; + + void getRegisteredMaterials(filament::MaterialInstance** materialList, + utils::CString* materialNameList) const; + + void getRegisteredMaterials(filament::MaterialInstance** materialList) const; + + void getRegisteredMaterialNames(utils::CString* materialNameList) const; + + private: + struct MaterialRegistryImpl; + MaterialRegistryImpl* mImpl; + }; + + struct Mesh { + utils::Entity renderable; + filament::VertexBuffer* vertexBuffer = nullptr; + filament::IndexBuffer* indexBuffer = nullptr; + }; + + /** + * Loads a filamesh renderable from the specified file. The material registry + * can be used to provide named materials. If a material found in the filamesh + * file cannot be matched to a material in the registry, a default material is + * used instead. The default material can be overridden by adding a material + * named "DefaultMaterial" to the registry. + */ + static Mesh loadMeshFromFile(filament::Engine* engine, + const utils::Path& path, + MaterialRegistry& materials); + + /** + * Loads a filamesh renderable from an in-memory buffer. The material registry + * can be used to provide named materials. If a material found in the filamesh + * file cannot be matched to a material in the registry, a default material is + * used instead. The default material can be overridden by adding a material + * named "DefaultMaterial" to the registry. + */ + static Mesh loadMeshFromBuffer(filament::Engine* engine, + void const* data, Callback destructor, void* user, + MaterialRegistry& materials); + + /** + * Loads a filamesh renderable from an in-memory buffer. The material registry + * can be used to provide named materials. All the primitives of the decoded + * renderable are assigned the specified default material. + */ + static Mesh loadMeshFromBuffer(filament::Engine* engine, + void const* data, Callback destructor, void* user, + filament::MaterialInstance* defaultMaterial); +}; + +} // namespace filamesh + +#endif // TNT_FILAMENT_FILAMESHIO_MESHREADER_H diff --git a/package/android/libs/filament/include/geometry/SurfaceOrientation.h b/package/android/libs/filament/include/geometry/SurfaceOrientation.h new file mode 100644 index 00000000..e9ad75bb --- /dev/null +++ b/package/android/libs/filament/include/geometry/SurfaceOrientation.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_GEOMETRY_SURFACEORIENTATION_H +#define TNT_GEOMETRY_SURFACEORIENTATION_H + +#include +#include +#include + +#include + +namespace filament { + +/** + * Mesh-related utilities. + */ +namespace geometry { + +struct OrientationBuilderImpl; +struct OrientationImpl; + +/** + * The surface orientation helper can be used to populate Filament-style TANGENTS buffers. + */ +class UTILS_PUBLIC SurfaceOrientation { +public: + + /** + * The Builder is used to construct an immutable surface orientation helper. + * + * Clients provide pointers into their own data, which is synchronously consumed during build(). + * At a minimum, clients must supply a vertex count. They can supply data in any of the + * following combinations: + * + * 1. normals only ........................... not recommended, selects arbitrary orientation + * 2. normals + tangents ..................... sign of W determines bitangent orientation + * 3. normals + uvs + positions + indices .... selects Lengyel’s Method + * 4. positions + indices .................... generates normals for flat shading only + * + * Additionally, the client-side data has the following type constraints: + * + * - Normals must be float3 + * - Tangents must be float4 + * - UVs must be float2 + * - Positions must be float3 + * - Triangles must be uint3 or ushort3 + * + * Currently, mikktspace is not supported because it requires re-indexing the mesh. Instead + * we use the method described by Eric Lengyel in "Foundations of Game Engine Development" + * (Volume 2, Chapter 7). + */ + class Builder { + public: + Builder() noexcept; + ~Builder() noexcept; + Builder(Builder&& that) noexcept; + Builder& operator=(Builder&& that) noexcept; + + /** + * This attribute is required. + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + Builder& normals(const filament::math::float3*, size_t stride = 0) noexcept; + Builder& tangents(const filament::math::float4*, size_t stride = 0) noexcept; + Builder& uvs(const filament::math::float2*, size_t stride = 0) noexcept; + Builder& positions(const filament::math::float3*, size_t stride = 0) noexcept; + + Builder& triangleCount(size_t triangleCount) noexcept; + Builder& triangles(const filament::math::uint3*) noexcept; + Builder& triangles(const filament::math::ushort3*) noexcept; + + /** + * Generates quats or returns null if the submitted data is an incomplete combination. + */ + SurfaceOrientation* build(); + + private: + OrientationBuilderImpl* mImpl; + Builder(const Builder&) = delete; + Builder& operator=(const Builder&) = delete; + }; + + ~SurfaceOrientation() noexcept; + SurfaceOrientation(SurfaceOrientation&& that) noexcept; + SurfaceOrientation& operator=(SurfaceOrientation&& that) noexcept; + + /** + * Returns the vertex count. + */ + size_t getVertexCount() const noexcept; + + /** + * Converts quaternions into the desired output format and writes up to "quatCount" + * to the given output pointer. Normally quatCount should be equal to the vertex count. + * The optional stride is the desired quat-to-quat stride in bytes. + * @{ + */ + void getQuats(filament::math::quatf* out, size_t quatCount, size_t stride = 0) const noexcept; + void getQuats(filament::math::short4* out, size_t quatCount, size_t stride = 0) const noexcept; + void getQuats(filament::math::quath* out, size_t quatCount, size_t stride = 0) const noexcept; + /** + * @} + */ + +private: + SurfaceOrientation(OrientationImpl*) noexcept; + SurfaceOrientation(const SurfaceOrientation&) = delete; + SurfaceOrientation& operator=(const SurfaceOrientation&) = delete; + OrientationImpl* mImpl; + friend struct OrientationBuilderImpl; +}; + +} // namespace geometry +} // namespace filament + +#endif // TNT_GEOMETRY_SURFACEORIENTATION_H diff --git a/package/android/libs/filament/include/geometry/TangentSpaceMesh.h b/package/android/libs/filament/include/geometry/TangentSpaceMesh.h new file mode 100644 index 00000000..980e81ac --- /dev/null +++ b/package/android/libs/filament/include/geometry/TangentSpaceMesh.h @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef TNT_GEOMETRY_TANGENTSPACEMESH_H +#define TNT_GEOMETRY_TANGENTSPACEMESH_H + +#include +#include +#include + +#include + +namespace filament { +namespace geometry { + +struct TangentSpaceMeshInput; +struct TangentSpaceMeshOutput; + + /** + * This class builds Filament-style TANGENTS buffers given an input mesh. + * + * This class enables the client to chose between several algorithms. The client can retrieve the + * result through the `get` methods on the class. If the chosen algorithm did not remesh the input, + * the client is advised to just use the data they provided instead of querying. For example, if + * the chosen method is Algorithm::FRISVAD, then the client should not need to call getPositions(). + * We will simply copy from the input `positions` in that case. + * + * If the client calls getPositions() and positions were not provided as input, we will throw + * and exception. Similar behavior will apply to UVs. + * + * This class supersedes the implementation in SurfaceOrientation.h + */ +class TangentSpaceMesh { +public: + enum class Algorithm : uint8_t { + /** + * default + * + * Tries to select the best possible algorithm given the input. The corresponding algorithms + * are detailed in the corresponding enums. + *
+         *   INPUT                                  ALGORITHM
+         *   -----------------------------------------------------------
+         *   normals                                FRISVAD
+         *   positions + indices                    FLAT_SHADING
+         *   normals + uvs + positions + indices    MIKKTSPACE
+         * 
+ */ + DEFAULT = 0, + + /** + * mikktspace + * + * **Requires**: `normals + uvs + positions + indices`
+ * **Reference**: + * - Mikkelsen, M., 2008. Simulation of wrinkled surfaces revisited. + * - https://github.com/mmikk/MikkTSpace + * - https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview + * + * **Note**: Will remesh + */ + MIKKTSPACE = 1, + + /** + * Lengyel's method + * + * **Requires**: `normals + uvs + positions + indices`
+ * **Reference**: Lengyel, E., 2019. Foundations of Game Engine Development: Rendering. Terathon + * Software LLC.. (Chapter 7) + */ + LENGYEL = 2, + + /** + * Hughes-Moller method + * + * **Requires**: `normals`
+ * **Reference**: + * - Hughes, J.F. and Moller, T., 1999. Building an orthonormal basis from a unit + * vector. journal of graphics tools, 4(4), pp.33-35. + * - Parker, S.G., Bigler, J., Dietrich, A., Friedrich, H., Hoberock, J., Luebke, D., + * McAllister, D., McGuire, M., Morley, K., Robison, A. and Stich, M., 2010. + * Optix: a general purpose ray tracing engine. Acm transactions on graphics (tog), + * 29(4), pp.1-13. + * **Note**: We implement the Optix variant, which is documented in the second reference above. + */ + HUGHES_MOLLER = 3, + + /** + * Frisvad's method + * + * **Requires**: `normals`
+ * **Reference**: + * - Frisvad, J.R., 2012. Building an orthonormal basis from a 3D unit vector without + * normalization. Journal of Graphics Tools, 16(3), pp.151-159. + * - http://people.compute.dtu.dk/jerf/code/hairy/ + */ + FRISVAD = 4, + }; + + /** + * This enum specifies the auxiliary attributes of each vertex that can be provided as input. + * These attributes do not affect the computation of the tangent space, but they will be + * properly mapped when a remeshing is carried out. + */ + enum class AuxAttribute : uint8_t { + UV1 = 0x0, + COLORS = 0x1, + JOINTS = 0x2, + WEIGHTS = 0x3, + }; + + using InData = std::variant; + + /** + * Use this class to provide input to the TangentSpaceMesh computation. **Important**: + * Computation of the tangent space is intended to be synchronous (working on the same thread). + * Client is expected to keep the input immutable and in a good state for the duration of both + * computation *and* query. That is, when querying the result of the tangent spaces, part of the + * result might depend on the input data. + */ + class Builder { + public: + Builder() noexcept; + ~Builder() noexcept; + + /** + * Move constructor + */ + Builder(Builder&& that) noexcept; + + /** + * Move constructor + */ + Builder& operator=(Builder&& that) noexcept; + + Builder(Builder const&) = delete; + Builder& operator=(Builder const&) = delete; + + /** + * Client must provide this parameter + * + * @param vertexCount The input number of vertcies + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + /** + * @param normals The input normals + * @param stride The stride for iterating through `normals` + * @return Builder + */ + Builder& normals(filament::math::float3 const* normals, size_t stride = 0) noexcept; + + /** + * @param tangents The input tangents. The `w` component is for use with + * Algorithm::SIGN_OF_W. + * @param stride The stride for iterating through `tangents` + * @return Builder + */ + Builder& tangents(filament::math::float4 const* tangents, size_t stride = 0) noexcept; + + /** + * @param uvs The input uvs + * @param stride The stride for iterating through `uvs` + * @return Builder + */ + Builder& uvs(filament::math::float2 const* uvs, size_t stride = 0) noexcept; + + /** + * Sets "auxiliary" attributes that will be properly mapped when remeshed. + * + * @param attribute The attribute of the data to be stored + * @param data The data to be store + * @param stride The stride for iterating through `attribute` + * @return Builder + */ + Builder& aux(AuxAttribute attribute, InData data, size_t stride = 0) noexcept; + + /** + * @param positions The input positions + * @param stride The stride for iterating through `positions` + * @return Builder + */ + Builder& positions(filament::math::float3 const* positions, size_t stride = 0) noexcept; + + /** + * @param triangleCount The input number of triangles + * @return Builder + */ + Builder& triangleCount(size_t triangleCount) noexcept; + + /** + * @param triangles The triangles in 32-bit indices + * @return Builder + */ + Builder& triangles(filament::math::uint3 const* triangles) noexcept; + + /** + * @param triangles The triangles in 16-bit indices + * @return Builder + */ + Builder& triangles(filament::math::ushort3 const* triangles) noexcept; + + /** + * The Client can provide an algorithm hint to produce the tangents. + * + * @param algorithm The algorithm hint. + * @return Builder + */ + Builder& algorithm(Algorithm algorithm) noexcept; + + /** + * Computes the tangent space mesh. The resulting mesh object is owned by the callee. The + * callee must call TangentSpaceMesh::destroy on the object once they are finished with it. + * + * The state of the Builder will be reset after each call to build(). The client needs to + * populate the builder with parameters again if they choose to re-use it. + * + * @return A TangentSpaceMesh + */ + TangentSpaceMesh* build(); + + private: + TangentSpaceMesh* mMesh = nullptr; + }; + + /** + * Destroy the mesh object + * @param mesh A pointer to a TangentSpaceMesh ready to be destroyed + */ + static void destroy(TangentSpaceMesh* mesh) noexcept; + + /** + * Move constructor + */ + TangentSpaceMesh(TangentSpaceMesh&& that) noexcept; + + /** + * Move constructor + */ + TangentSpaceMesh& operator=(TangentSpaceMesh&& that) noexcept; + + TangentSpaceMesh(TangentSpaceMesh const&) = delete; + TangentSpaceMesh& operator=(TangentSpaceMesh const&) = delete; + + /** + * Number of output vertices + * + * The number of output vertices can be the same as the input if the selected algorithm did not + * "remesh" the input. + * + * @return The number of vertices + */ + size_t getVertexCount() const noexcept; + + /** + * Get output vertex positions. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). The output vertices can be the same as the input if the selected algorithm did + * not "remesh" the input. The remeshed vertices are not guarranteed to have correlation in + * order with the input mesh. + * + * @param out Client-allocated array that will be used for copying out positions. + * @param stride Stride for iterating through `out` + */ + void getPositions(filament::math::float3* out, size_t stride = 0) const; + + /** + * Get output UVs. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). The output uvs can be the same as the input if the selected algorithm did + * not "remesh" the input. The remeshed UVs are not guarranteed to have correlation in order + * with the input mesh. + * + * @param out Client-allocated array that will be used for copying out UVs. + * @param stride Stride for iterating through `out` + */ + void getUVs(filament::math::float2* out, size_t stride = 0) const; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 32-bit floating points. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::quatf* out, size_t stride = 0) const noexcept; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 16-bit signed integers. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::short4* out, size_t stride = 0) const noexcept; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 16-bit floating points. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::quath* out, size_t stride = 0) const noexcept; + + /** + * Get output auxiliary attributes. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out attribute as T + * @param stride Stride for iterating through `out` + */ + template + using is_supported_aux_t = + typename std::enable_if::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + template> + void getAux(AuxAttribute attribute, T* out, size_t stride = 0) const noexcept; + + /** + * Get number of output triangles. + * The number of output triangles is the same as the number of input triangles. However, when a + * "remesh" is carried out the output triangles are not guarranteed to have any correlation with + * the input. + * + * @return The number of vertices + */ + size_t getTriangleCount() const noexcept; + + /** + * Get output triangles. + * This method assumes that the `out` param provided by the client is at least of + * getTriangleCount() length. If the client calls getTriangles() and triangles were not + * provided as input, we will throw and exception. + * + * @param out Client's array for the output triangles in unsigned 32-bit indices. + */ + void getTriangles(filament::math::uint3* out) const; + + /** + * Get output triangles. + * This method assumes that the `out` param provided by the client is at least of + * getTriangleCount() length. If the client calls getTriangles() and triangles were not + * provided as input, we will throw and exception. + * + * @param out Client's array for the output triangles in unsigned 16-bit indices. + */ + void getTriangles(filament::math::ushort3* out) const; + + /** + * @return Whether the TBN algorithm remeshed the input. + */ + bool remeshed() const noexcept; + +private: + ~TangentSpaceMesh() noexcept; + TangentSpaceMesh() noexcept; + TangentSpaceMeshInput* mInput; + TangentSpaceMeshOutput* mOutput; + + friend class Builder; +}; + +} // namespace geometry +} // namespace filament + +#endif //TNT_GEOMETRY_TANGENTSPACEMESH_H diff --git a/package/android/libs/filament/include/geometry/Transcoder.h b/package/android/libs/filament/include/geometry/Transcoder.h new file mode 100644 index 00000000..805c2609 --- /dev/null +++ b/package/android/libs/filament/include/geometry/Transcoder.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_GEOMETRY_TRANSCODER_H +#define TNT_GEOMETRY_TRANSCODER_H + +#include + +#include +#include + +namespace filament { +namespace geometry { + +enum class ComponentType { + BYTE, //!< If normalization is enabled, this maps from [-127,127] to [-1,+1] + UBYTE, //!< If normalization is enabled, this maps from [0,255] to [0, +1] + SHORT, //!< If normalization is enabled, this maps from [-32767,32767] to [-1,+1] + USHORT, //!< If normalization is enabled, this maps from [0,65535] to [0, +1] + HALF, //!< 1 sign bit, 5 exponent bits, and 5 mantissa bits. + FLOAT, //!< Standard 32-bit float +}; + +/** + * Creates a function object that can convert vertex attribute data into tightly packed floats. + * + * This is especially useful for 3-component formats which are not supported by all backends. + * e.g. The Vulkan minspec includes float3 but not short3. + * + * Usage Example: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * using filament::geometry::Transcoder; + * using filament::geometry::ComponentType; + * + * Transcoder transcode({ + * .componentType = ComponentType::BYTE, + * .normalized = true, + * .componentCount = 3, + * .inputStrideBytes = 0 + * }); + * + * transcode(outputPtr, inputPtr, count); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The interpretation of signed normalized data is consistent with Vulkan and OpenGL ES 3.0+. + * Note that this slightly differs from earlier versions of OpenGL ES. For example, a signed byte + * value of -127 maps exactly to -1.0f under ES3 and VK rules, but not ES2. + */ +class UTILS_PUBLIC Transcoder { +public: + /** + * Describes the format of all input data that get passed to this transcoder object. + */ + struct Config { + ComponentType componentType; + bool normalized; + uint32_t componentCount; + uint32_t inputStrideBytes = 0; //!< If stride is 0, the transcoder assumes tight packing. + }; + + /** + * Creates an immutable function object with the specified configuration. + * + * The config is not passed by const reference to allow for type inference at the call site. + */ + Transcoder(Config config) noexcept : mConfig(config) {} + + /** + * Converts arbitrary data into tightly packed 32-bit floating point values. + * + * If target is non-null, writes up to "count" items into target and returns the number of bytes + * actually written. + * + * If target is null, returns the number of bytes required. + * + * @param target Client owned area to write into, or null for a size query + * @param source Pointer to the data to read from (does not get retained) + * @param count The maximum number of items to write (i.e. number of float3 values, not bytes) + * @return Number of bytes required to contain "count" items after conversion to packed floats + * + */ + size_t operator()(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, + size_t count) const noexcept; + +private: + const Config mConfig; +}; + +} // namespace geometry +} // namespace filament + +#endif // TNT_GEOMETRY_TRANSCODER_H diff --git a/package/android/libs/filament/include/gltfio/Animator.h b/package/android/libs/filament/include/gltfio/Animator.h new file mode 100644 index 00000000..199555a4 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/Animator.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_ANIMATOR_H +#define GLTFIO_ANIMATOR_H + +#include +#include + +namespace filament::gltfio { + +struct FFilamentAsset; +struct FFilamentInstance; +struct AnimatorImpl; + +/** + * \class Animator Animator.h gltfio/Animator.h + * \brief Updates matrices according to glTF \c animation and \c skin definitions. + * + * Animator can be used for two things: + * - Updating matrices in filament::TransformManager components according to glTF \c animation definitions. + * - Updating bone matrices in filament::RenderableManager components according to glTF \c skin definitions. + * + * For a usage example, see the documentation for AssetLoader. + */ +class UTILS_PUBLIC Animator { +public: + /** + * Applies rotation, translation, and scale to entities that have been targeted by the given + * animation definition. Uses filament::TransformManager. + * + * @param animationIndex Zero-based index for the \c animation of interest. + * @param time Elapsed time of interest in seconds. + */ + void applyAnimation(size_t animationIndex, float time) const; + + /** + * Computes root-to-node transforms for all bone nodes, then passes + * the results into filament::RenderableManager::setBones. + * Uses filament::TransformManager and filament::RenderableManager. + * + * NOTE: this operation is independent of \c animation. + */ + 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. + * + * NOTE: this operation is independent of \c animation. + */ + void resetBoneMatrices(); + + /** Returns the number of \c animation definitions in the glTF asset. */ + size_t getAnimationCount() const; + + /** Returns the duration of the specified glTF \c animation in seconds. */ + float getAnimationDuration(size_t animationIndex) const; + + /** + * Returns a weak reference to the string name of the specified \c animation, or an + * empty string if none was specified. + */ + const char* getAnimationName(size_t animationIndex) const; + + // For internal use only. + void addInstance(FFilamentInstance* instance); + +private: + + /*! \cond PRIVATE */ + friend struct FFilamentAsset; + friend struct FFilamentInstance; + /*! \endcond */ + + // If "instance" is null, then this is the primary animator. + Animator(FFilamentAsset const* asset, FFilamentInstance* instance); + ~Animator(); + + Animator(const Animator& animator) = delete; + Animator(Animator&& animator) = delete; + Animator& operator=(const Animator&) = delete; + + AnimatorImpl* mImpl; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_ANIMATOR_H diff --git a/package/android/libs/filament/include/gltfio/AssetLoader.h b/package/android/libs/filament/include/gltfio/AssetLoader.h new file mode 100644 index 00000000..080538aa --- /dev/null +++ b/package/android/libs/filament/include/gltfio/AssetLoader.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_ASSETLOADER_H +#define GLTFIO_ASSETLOADER_H + +#include +#include + +#include +#include +#include + +#include + +namespace utils { + class EntityManager; + class NameComponentManager; +} + +/** + * Loader and pipeline for glTF 2.0 assets. + */ +namespace filament::gltfio { + +class NodeManager; + +/** + * \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h + * \brief Construction parameters for AssetLoader. + */ +struct AssetConfiguration { + //! The engine that the loader should pass to builder objects (e.g. + //! filament::VertexBuffer::Builder). + class filament::Engine* engine; + + //! Controls whether the loader uses filamat to generate materials on the fly, or loads a small + //! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's + //! responsibility. See createJitShaderProvider() and createUbershaderProvider(). + MaterialProvider* materials; + + //! Optional manager for associating string names with entities in the transform hierarchy. + utils::NameComponentManager* names = nullptr; + + //! Overrides the factory used for creating entities in the transform hierarchy. If this is not + //! specified, AssetLoader will use the singleton EntityManager associated with the current + //! process. + utils::EntityManager* entities = nullptr; + + //! Optional default node name for anonymous nodes + char* defaultNodeName = nullptr; +}; + +/** + * \class AssetLoader AssetLoader.h gltfio/AssetLoader.h + * \brief Consumes glTF content and produces FilamentAsset objects. + * + * AssetLoader consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a FilamentAsset + * object, which is a bundle of Filament textures, vertex buffers, index buffers, etc. An asset is + * composed of 1 or more FilamentInstance objects which contain entities and components. + * + * Clients must use AssetLoader to create and destroy FilamentAsset objects. This is similar to + * how filament::Engine is used to create and destroy core objects like VertexBuffer. + * + * AssetLoader does not fetch external buffer data or create textures on its own. Clients can use + * ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the + * code snippet below. + * + * AssetLoader also owns a cache of filament::Material objects that may be re-used across multiple + * loads. + * + * Example usage: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto engine = Engine::create(); + * auto materials = createJitShaderProvider(engine); + * auto decoder = createStbProvider(engine); + * auto loader = AssetLoader::create({engine, materials}); + * + * // Parse the glTF content and create Filament entities. + * std::vector content(...); + * FilamentAsset* asset = loader->createAsset(content.data(), content.size()); + * content.clear(); + * + * // Load buffers and textures from disk. + * ResourceLoader resourceLoader({engine, ".", true}); + * resourceLoader.addTextureProvider("image/png", decoder) + * resourceLoader.addTextureProvider("image/jpeg", decoder) + * resourceLoader.loadResources(asset); + * + * // Free the glTF hierarchy as it is no longer needed. + * asset->releaseSourceData(); + * + * // Add renderables to the scene. + * scene->addEntities(asset->getEntities(), asset->getEntityCount()); + * + * // Extract the animator interface from the FilamentInstance. + * auto animator = asset->getInstance()->getAnimator(); + * + * // Execute the render loop and play the first animation. + * do { + * animator->applyAnimation(0, time); + * animator->updateBoneMatrices(); + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } while (!quit); + * + * scene->removeEntities(asset->getEntities(), asset->getEntityCount()); + * loader->destroyAsset(asset); + * materials->destroyMaterials(); + * delete materials; + * delete decoder; + * AssetLoader::destroy(&loader); + * Engine::destroy(&engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC AssetLoader { +public: + + /** + * Creates an asset loader for the given configuration, which specifies the Filament engine. + * + * The engine is held weakly, used only for the creation and destruction of Filament objects. + * The optional name component manager can be used to assign names to renderables. + * The material source specifies whether to use filamat to generate materials on the fly, or to + * load a small set of precompiled ubershader materials. + */ + static AssetLoader* create(const AssetConfiguration& config); + + /** + * Frees the loader. + * + * This does not not automatically free the cache of materials, nor + * does it free the entities for created assets (see destroyAsset). + */ + static void destroy(AssetLoader** loader); + + /** + * Takes a pointer to the contents of a GLB or a JSON-based glTF 2.0 file and returns an asset + * with one instance, or null on failure. + */ + FilamentAsset* createAsset(const uint8_t* bytes, uint32_t nbytes); + + /** + * Consumes the contents of a glTF 2.0 file and produces a primary asset with one or more + * instances. The primary asset has ownership over the instances. + * + * The returned instances share their textures, materials, and vertex buffers with the primary + * asset. However each instance has its own unique set of entities, transform components, + * material instances, and renderable components. Instances are freed when the primary asset is + * freed. + * + * Light components are not instanced, they belong only to the primary asset. + * + * Clients must use ResourceLoader to load resources on the primary asset. + * + * The entity accessor and renderable stack API in the primary asset can be used to control the + * union of all instances. The individual FilamentInstance objects can be used to access each + * instance's partition of entities. Similarly, the Animator in the primary asset controls all + * instances. To animate instances individually, use FilamentInstance::getAnimator(). + * + * @param bytes the contents of a glTF 2.0 file (JSON or GLB) + * @param numBytes the number of bytes in "bytes" + * @param instances destination pointer, to be populated by the requested number of instances + * @param numInstances requested number of instances + * @return the primary asset that has ownership over all instances + */ + FilamentAsset* createInstancedAsset(const uint8_t* bytes, uint32_t numBytes, + FilamentInstance** instances, size_t numInstances); + + /** + * Adds a new instance to the asset. + * + * Use this with caution. It is more efficient to pre-allocate a max number of instances, and + * gradually add them to the scene as needed. Instances can also be "recycled" by removing and + * re-adding them to the scene. + * + * NOTE: destroyInstance() does not exist because gltfio favors flat arrays for storage of + * entity lists and instance lists, which would be slow to shift. We also wish to discourage + * create/destroy churn, as noted above. + * + * This cannot be called after FilamentAsset::releaseSourceData(). + * See also AssetLoader::createInstancedAsset(). + */ + FilamentInstance* createInstance(FilamentAsset* asset); + + /** + * Allows clients to enable diagnostic shading on newly-loaded assets. + */ + void enableDiagnostics(bool enable = true); + + /** + * Destroys the given asset, all of its associated Filament objects, and all associated + * FilamentInstance objects. + * + * This destroys entities, components, material instances, vertex buffers, index buffers, + * and textures. This does not necessarily immediately free all source data, since + * texture decoding or GPU uploading might be underway. + */ + void destroyAsset(const FilamentAsset* asset); + + /** + * Gets a weak reference to an array of cached materials, used internally to create material + * instances for assets. + */ + const filament::Material* const* getMaterials() const noexcept; + + /** + * Gets the number of cached materials. + */ + size_t getMaterialsCount() const noexcept; + + utils::NameComponentManager* getNames() const noexcept; + + NodeManager& getNodeManager() noexcept; + + MaterialProvider& getMaterialProvider() noexcept; + + /*! \cond PRIVATE */ +protected: + AssetLoader() noexcept = default; + ~AssetLoader() = default; + +public: + AssetLoader(AssetLoader const&) = delete; + AssetLoader(AssetLoader&&) = delete; + AssetLoader& operator=(AssetLoader const&) = delete; + AssetLoader& operator=(AssetLoader&&) = delete; + /*! \endcond */ +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_ASSETLOADER_H diff --git a/package/android/libs/filament/include/gltfio/FilamentAsset.h b/package/android/libs/filament/include/gltfio/FilamentAsset.h new file mode 100644 index 00000000..6408b363 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/FilamentAsset.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_FILAMENTASSET_H +#define GLTFIO_FILAMENTASSET_H + +#include +#include + +#include + +#include +#include + +namespace filament { + class Camera; + class Engine; + class MaterialInstance; + class Scene; +} + +namespace filament::gltfio { + +class Animator; +class FilamentInstance; + +/** + * \class FilamentAsset FilamentAsset.h gltfio/FilamentAsset.h + * \brief Owns a bundle of Filament objects that have been created by AssetLoader. + * + * For usage instructions, see the documentation for AssetLoader. + * + * This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has + * a filament::TransformManager component, and some entities also have \c Name, \c Renderable, + * \c Light, \c Camera, or \c Node components. + * + * In addition to the aforementioned entities, an asset has strong ownership over a list of + * filament::VertexBuffer, filament::IndexBuffer, filament::Texture, + * and, optionally, a simple animation engine (gltfio::Animator). + * + * Clients must use ResourceLoader to create filament::Texture objects, compute tangent quaternions, + * and upload data into vertex buffers and index buffers. + * + * \todo Only the default glTF scene is loaded, other glTF scenes are ignored. + */ +class UTILS_PUBLIC FilamentAsset { +public: + using Entity = utils::Entity; + using SceneMask = NodeManager::SceneMask; + + /** + * Gets the list of entities, one for each glTF node. All of these have a Transform component. + * Some of the returned entities may also have a Renderable component and/or a Light component. + */ + const Entity* getEntities() const noexcept; + + /** + * Gets the number of entities returned by getEntities(). + */ + size_t getEntityCount() const noexcept; + + /** + * Gets the list of entities in the scene representing lights. All of these have a Light component. + */ + const Entity* getLightEntities() const noexcept; + + /** + * Gets the number of entities returned by getLightEntities(). + */ + size_t getLightEntityCount() const noexcept; + + /** + * Gets the list of entities in the asset that have renderable components. + */ + const utils::Entity* getRenderableEntities() const noexcept; + + /** + * Gets the number of entities returned by getRenderableEntities(). + */ + size_t getRenderableEntityCount() const noexcept; + + /** + * Gets the list of entities in the scene representing cameras. All of these have a \c Camera + * component. + * + * Note about aspect ratios: + * gltfio always uses an aspect ratio of 1.0 when setting the projection matrix for perspective + * cameras. gltfio then sets the camera's scaling matrix with the aspect ratio specified in the + * glTF file (if present). + * + * The camera's scaling matrix allows clients to adjust the aspect ratio independently from the + * camera's projection. + * + * To change the aspect ratio of the glTF camera: + * + * camera->setScaling(double4 {1.0 / newAspectRatio, 1.0, 1.0, 1.0}); + * + * @see filament::Camera::setScaling + */ + const Entity* getCameraEntities() const noexcept; + + /** + * Gets the number of entities returned by getCameraEntities(). + */ + size_t getCameraEntityCount() const noexcept; + + /** + * Gets the transform root for the asset, which has no matching glTF node. + * + * This node exists for convenience, allowing users to transform the entire asset. For instanced + * assets, this is a "super root" where each of its children is a root in a particular instance. + * This allows users to transform all instances en masse if they wish to do so. + */ + Entity getRoot() const noexcept; + + /** + * Pops a ready renderable off the queue, or returns 0 if no renderables have become ready. + * + * NOTE: To determine the progress percentage or completion status, please use + * ResourceLoader#asyncGetLoadProgress. To get the number of ready renderables, + * please use popRenderables(). + * + * This method allows clients to progressively add the asset's renderables to the scene as + * textures gradually become ready through asynchronous loading. For example, on every frame + * progressive applications can do something like this: + * + * while (Entity e = popRenderable()) { scene.addEntity(e); } + * + * Progressive reveal is not supported for dynamically added instances. + * + * \see ResourceLoader#asyncBeginLoad + * \see popRenderables() + */ + Entity popRenderable() noexcept; + + /** + * Pops up to "count" ready renderables off the queue, or returns the available number. + * + * The given pointer should either be null or point to memory that can hold up to count + * entities. If the pointer is null, returns the number of available renderables. Otherwise + * returns the number of entities that have been written. + * + * \see ResourceLoader#asyncBeginLoad + */ + size_t popRenderables(Entity* entities, size_t count) noexcept; + + /** Gets resource URIs for all externally-referenced buffers. */ + const char* const* getResourceUris() const noexcept; + + /** Gets the number of resource URIs returned by getResourceUris(). */ + size_t getResourceUriCount() const noexcept; + + /** + * Gets the bounding box computed from the supplied min / max values in glTF accessors. + * + * This does not return a bounding box over all FilamentInstance, it's just a straightforward + * AAAB that can be determined at load time from the asset data. + */ + filament::Aabb getBoundingBox() const noexcept; + + /** Gets the NameComponentManager label for the given entity, if it exists. */ + const char* getName(Entity) const noexcept; + + /** Returns the first entity with the given name, or 0 if none exist. */ + Entity getFirstEntityByName(const char* name) noexcept; + + /** + * Gets a list of entities with the given name. + * + * @param name Null-terminated string to match. + * @param entities Pointer to an array to populate. + * @param maxCount Maximum number of entities to retrieve. + * + * @return If entities is non-null, the number of entities written to the entity pointer. + * Otherwise this returns the number of entities with the given name. + */ + size_t getEntitiesByName(const char* name, Entity* entities, + size_t maxCount) const noexcept; + + /** + * Gets a list of entities whose names start with the given prefix. + * + * @param prefix Null-terminated prefix string to match. + * @param entities Pointer to an array to populate. + * @param maxCount Maximum number of entities to retrieve. + * + * @return If entities is non-null, the number of entities written to the entity pointer. + * Otherwise this returns the number of entities with the given prefix. + */ + size_t getEntitiesByPrefix(const char* prefix, Entity* entities, + size_t maxCount) const noexcept; + + /** Gets the glTF extras string for a specific node, or for the asset, if it exists. */ + const char* getExtras(Entity entity = {}) const noexcept; + + /** + * Gets the morph target name at the given index in the given entity. + */ + const char* getMorphTargetNameAt(Entity entity, size_t targetIndex) const noexcept; + + /** + * Returns the number of morph targets in the given entity. + */ + size_t getMorphTargetCountAt(Entity entity) const noexcept; + + /** + * Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy + * for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it. + */ + Entity getWireframe() noexcept; + + /** + * Returns the Filament engine associated with the AssetLoader that created this asset. + */ + filament::Engine* getEngine() const noexcept; + + /** + * Reclaims CPU-side memory for URI strings, binding lists, and raw animation data. + * + * This should only be called after ResourceLoader::loadResources(). + * If this is an instanced asset, this prevents creation of new instances. + */ + void releaseSourceData() noexcept; + + /** + * Returns a weak reference to the underlying cgltf hierarchy. This becomes invalid after + * calling releaseSourceData(). + */ + const void* getSourceAsset() noexcept; + + /** + * Returns the number of scenes in the asset. + */ + size_t getSceneCount() const noexcept; + + /** + * Returns the name of the given scene. + * + * Returns null if the given scene does not have a name or is out of bounds. + */ + const char* getSceneName(size_t sceneIndex) const noexcept; + + /** + * Adds entities to a Filament scene only if they belong to at least one of the given glTF + * scenes. + * + * This is just a helper that provides an alternative to directly calling scene->addEntities() + * and provides filtering functionality. + */ + void addEntitiesToScene(filament::Scene& targetScene, const Entity* entities, size_t count, + SceneMask sceneFilter) const; + + /** + * Releases ownership of entities and their Filament components. + * + * This makes the client take responsibility for destroying Filament + * components (e.g. Renderable, TransformManager component) as well as + * the underlying entities. + */ + void detachFilamentComponents() noexcept; + + bool areFilamentComponentsDetached() const noexcept; + + /** + * Convenience function to get the first instance, or null if it doesn't exist. + */ + FilamentInstance* getInstance() noexcept { + return getAssetInstanceCount() > 0 ? getAssetInstances()[0] : nullptr; + } + + /*! \cond PRIVATE */ + + FilamentInstance** getAssetInstances() noexcept; + size_t getAssetInstanceCount() const noexcept; + +protected: + FilamentAsset() noexcept = default; + ~FilamentAsset() = default; + +public: + FilamentAsset(FilamentAsset const&) = delete; + FilamentAsset(FilamentAsset&&) = delete; + FilamentAsset& operator=(FilamentAsset const&) = delete; + FilamentAsset& operator=(FilamentAsset&&) = delete; + /*! \endcond */ +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_FILAMENTASSET_H diff --git a/package/android/libs/filament/include/gltfio/FilamentInstance.h b/package/android/libs/filament/include/gltfio/FilamentInstance.h new file mode 100644 index 00000000..04199639 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/FilamentInstance.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef GLTFIO_FILAMENTINSTANCE_H +#define GLTFIO_FILAMENTINSTANCE_H + +#include +#include + +#include + +namespace filament { +class MaterialInstance; +} + +namespace filament::gltfio { + +class Animator; +class FilamentAsset; + +/** + * \class FilamentInstance FilamentInstance.h gltfio/FilamentInstance.h + * \brief Provides access to a hierarchy of entities that have been instanced from a glTF asset. + * + * Every entity has a TransformManager component, and some entities also have \c Name or + * \c Renderable components. + * + * \see AssetLoader::createInstancedAsset() + */ +class UTILS_PUBLIC FilamentInstance { +public: + /** + * Gets the owner of this instance. + */ + FilamentAsset const* getAsset() const noexcept; + + /** + * Gets the list of entities in this instance, one for each glTF node. All of these have a + * Transform component. Some of the returned entities may also have a Renderable component or + * Name component. + */ + const utils::Entity* getEntities() const noexcept; + + /** + * Gets the number of entities returned by getEntities(). + */ + size_t getEntityCount() const noexcept; + + /** Gets the transform root for the instance, which has no matching glTF node. */ + utils::Entity getRoot() const noexcept; + + /** + * Applies the given material variant to all primitives in this instance. + * + * Ignored if variantIndex is out of bounds. + */ + void applyMaterialVariant(size_t variantIndex) noexcept; + + /** + * Returns the number of material variants in the asset. + */ + size_t getMaterialVariantCount() const noexcept; + + /** + * Returns the name of the given material variant, or null if it is out of bounds. + */ + const char* getMaterialVariantName(size_t variantIndex) const noexcept; + + /** + * Returns the animation engine for the instance. + * + * Note that an animator can be obtained either from an individual instance, or from the + * originating FilamentAsset. In the latter case, the animation frame is shared amongst all + * instances. If individual control is desired, users must obtain the animator from the + * individual instances. + * + * The animator is owned by the asset and should not be manually deleted. + */ + Animator* getAnimator() noexcept; + + /** + * Gets the number of skins. + */ + size_t getSkinCount() const noexcept; + + /** + * Gets the skin name at skin index. + */ + const char* getSkinNameAt(size_t skinIndex) const noexcept; + + /** + * Gets the number of joints at skin index. + */ + size_t getJointCountAt(size_t skinIndex) const noexcept; + + /** + * Gets joints at skin index. + */ + const utils::Entity* getJointsAt(size_t skinIndex) const noexcept; + + /** + * Attaches the given skin to the given node, which must have an associated mesh with + * BONE_INDICES and BONE_WEIGHTS attributes. + * + * This is a no-op if the given skin index or target is invalid. + */ + void attachSkin(size_t skinIndex, utils::Entity target) noexcept; + + /** + * Detaches the given skin from the given node. + * + * This is a no-op if the given skin index or target is invalid. + */ + void detachSkin(size_t skinIndex, utils::Entity target) noexcept; + + /** + * Gets inverse bind matrices for all joints at the given skin index. + * + * See getJointCountAt for determining the number of matrices returned (i.e. the number of joints). + */ + math::mat4f const* getInverseBindMatricesAt(size_t skinIndex) const; + + /** + * Resets the AABB on all renderables by manually computing the bounding box. + * + * THIS IS ONLY USEFUL FOR MALFORMED ASSETS THAT DO NOT HAVE MIN/MAX SET UP CORRECTLY. + * + * Does not affect the return value of getBoundingBox() on the owning asset. + * Cannot be called after releaseSourceData() on the owning asset. + * Can only be called after loadResources() or asyncBeginLoad(). + */ + void recomputeBoundingBoxes(); + + /** + * Gets the axis-aligned bounding box from the supplied min / max values in glTF accessors. + * + * If recomputeBoundingBoxes() has been called, then this returns the recomputed AABB. + */ + Aabb getBoundingBox() const noexcept; + + /** Gets all material instances. These are already bound to renderables. */ + const MaterialInstance* const* getMaterialInstances() const noexcept; + + /** Gets all material instances (non-const). These are already bound to renderables. */ + MaterialInstance* const* getMaterialInstances() noexcept; + + /** Gets the number of materials returned by getMaterialInstances(). */ + size_t getMaterialInstanceCount() const noexcept; + + /** + * Releases ownership of material instances. + * + * This makes the client take responsibility for destroying MaterialInstance + * objects. The getMaterialInstances query becomes invalid after detachment. + */ + void detachMaterialInstances(); +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_FILAMENTINSTANCE_H diff --git a/package/android/libs/filament/include/gltfio/MaterialProvider.h b/package/android/libs/filament/include/gltfio/MaterialProvider.h new file mode 100644 index 00000000..f62d667b --- /dev/null +++ b/package/android/libs/filament/include/gltfio/MaterialProvider.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_MATERIALPROVIDER_H +#define GLTFIO_MATERIALPROVIDER_H + +#include +#include +#include + +#include + +#include +#include + +namespace filament::gltfio { + +enum class AlphaMode : uint8_t { + OPAQUE, + MASK, + BLEND +}; + +// The following struct gets hashed so all padding bits should be explicit. +// Tell the compiler to emit a warning if it adds any padding. +UTILS_WARNING_PUSH +UTILS_WARNING_ENABLE_PADDED + +/** + * \struct MaterialKey MaterialProvider.h gltfio/MaterialProvider.h + * \brief Small POD structure that specifies the requirements for a glTF material. + * \note This key is processed by MurmurHashFn so please make padding explicit. + */ +struct alignas(4) MaterialKey { + // -- 32 bit boundary -- + bool doubleSided : 1; + bool unlit : 1; + bool hasVertexColors : 1; + bool hasBaseColorTexture : 1; + bool hasNormalTexture : 1; + bool hasOcclusionTexture : 1; + bool hasEmissiveTexture : 1; + bool useSpecularGlossiness : 1; + AlphaMode alphaMode : 4; + bool enableDiagnostics : 4; + union { + struct { + bool hasMetallicRoughnessTexture : 1; + uint8_t metallicRoughnessUV : 7; + }; + struct { + bool hasSpecularGlossinessTexture : 1; + uint8_t specularGlossinessUV : 7; + }; + }; + uint8_t baseColorUV; + // -- 32 bit boundary -- + bool hasClearCoatTexture : 1; + uint8_t clearCoatUV : 7; + bool hasClearCoatRoughnessTexture : 1; + uint8_t clearCoatRoughnessUV : 7; + bool hasClearCoatNormalTexture : 1; + uint8_t clearCoatNormalUV : 7; + bool hasClearCoat : 1; + bool hasTransmission : 1; + bool hasTextureTransforms : 6; + // -- 32 bit boundary -- + uint8_t emissiveUV; + uint8_t aoUV; + uint8_t normalUV; + bool hasTransmissionTexture : 1; + uint8_t transmissionUV : 7; + // -- 32 bit boundary -- + bool hasSheenColorTexture : 1; + uint8_t sheenColorUV : 7; + bool hasSheenRoughnessTexture : 1; + uint8_t sheenRoughnessUV : 7; + bool hasVolumeThicknessTexture : 1; + uint8_t volumeThicknessUV : 7; + bool hasSheen : 1; + bool hasIOR : 1; + bool hasVolume : 1; + uint8_t padding : 5; +}; + +static_assert(sizeof(MaterialKey) == 16, "MaterialKey has unexpected size."); + +UTILS_WARNING_POP + +bool operator==(const MaterialKey& k1, const MaterialKey& k2); + +// Define a mapping from a uv set index in the source asset to one of Filament's uv sets. +enum UvSet : uint8_t { UNUSED, UV0, UV1 }; +constexpr int UvMapSize = 8; +using UvMap = std::array; + +inline uint8_t getNumUvSets(const UvMap& uvmap) { + return std::max({ + uvmap[0], uvmap[1], uvmap[2], uvmap[3], + uvmap[4], uvmap[5], uvmap[6], uvmap[7], + }); +}; + +/** + * \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h + * \brief Interface to a provider of glTF materials (has two implementations). + * + * - The \c JitShaderProvider implementation generates materials at run time (which can be slow) and + * requires the filamat library, but produces streamlined shaders. See createJitShaderProvider(). + * + * - The \c UbershaderProvider implementation uses a small number of pre-built materials with complex + * fragment shaders, but does not require any run time work or usage of filamat. See + * createUbershaderProvider(). + * + * Both implementations of MaterialProvider maintain a small cache of materials which must be + * explicitly freed using destroyMaterials(). These materials are not freed automatically when the + * MaterialProvider is destroyed, which allows clients to take ownership if desired. + * + */ +class UTILS_PUBLIC MaterialProvider { +public: + virtual ~MaterialProvider() {} + + /** + * Creates or fetches a compiled Filament material, then creates an instance from it. + * + * @param config Specifies requirements; might be mutated due to resource constraints. + * @param uvmap Output argument that gets populated with a small table that maps from a glTF uv + * index to a Filament uv index. + * @param label Optional tag that is not a part of the cache key. + * @param extras Optional extras as stringified JSON (not a part of the cache key). + * Does not store the pointer. + */ + virtual MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, + const char* label = "material", const char* extras = nullptr) = 0; + + /** + * Creates or fetches a compiled Filament material corresponding to the given config. + */ + virtual Material* getMaterial(MaterialKey* config, UvMap* uvmap, + const char* label = "material") { return nullptr; } + + /** + * Gets a weak reference to the array of cached materials. + */ + virtual const Material* const* getMaterials() const noexcept = 0; + + /** + * Gets the number of cached materials. + */ + virtual size_t getMaterialsCount() const noexcept = 0; + + /** + * Destroys all cached materials. + * + * This is not called automatically when MaterialProvider is destroyed, which allows + * clients to take ownership of the cache if desired. + */ + virtual void destroyMaterials() = 0; + + /** + * Returns true if the presence of the given vertex attribute is required. + * + * Some types of providers (e.g. ubershader) require dummy attribute values + * if the glTF model does not provide them. + */ + virtual bool needsDummyData(VertexAttribute attrib) const noexcept = 0; +}; + +void constrainMaterial(MaterialKey* key, UvMap* uvmap); + +void processShaderString(std::string* shader, const UvMap& uvmap, + const MaterialKey& config); + +/** + * Creates a material provider that builds materials on the fly, composing GLSL at run time. + * + * @param optimizeShaders Optimizes shaders, but at significant cost to construction time. + * @return New material provider that can build materials at run time. + * + * Requires \c libfilamat to be linked in. Not available in \c libgltfio_core. + * + * @see createUbershaderProvider + */ +UTILS_PUBLIC +MaterialProvider* createJitShaderProvider(Engine* engine, bool optimizeShaders = false); + +/** + * Creates a material provider that loads a small set of pre-built materials. + * + * @return New material provider that can quickly load a material from a cache. + * + * @see createJitShaderProvider + */ +UTILS_PUBLIC +MaterialProvider* createUbershaderProvider(Engine* engine, const void* archive, + size_t archiveByteCount); + +} // namespace filament::gltfio + +#endif // GLTFIO_MATERIALPROVIDER_H diff --git a/package/android/libs/filament/include/gltfio/NodeManager.h b/package/android/libs/filament/include/gltfio/NodeManager.h new file mode 100644 index 00000000..04f7bd6d --- /dev/null +++ b/package/android/libs/filament/include/gltfio/NodeManager.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#ifndef GLTFIO_NODEMANAGER_H +#define GLTFIO_NODEMANAGER_H + +#include + +#include +#include +#include +#include +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament::gltfio { + +class FNodeManager; + +/** + * NodeManager is used to add annotate entities with glTF-specific information. + * + * Node components are created by gltfio and exposed to users to allow inspection. + * + * Nodes do not store the glTF hierarchy or names; see TransformManager and NameComponentManager. + */ +class UTILS_PUBLIC NodeManager { +public: + using Instance = utils::EntityInstance; + using Entity = utils::Entity; + using CString = utils::CString; + using SceneMask = utils::bitset32; + + static constexpr size_t MAX_SCENE_COUNT = 32; + + /** + * Returns whether a particular Entity is associated with a component of this NodeManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(Entity e) const noexcept; + + /** + * Gets an Instance representing the node component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the node component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(Entity e) const noexcept; + + /** + * Creates a node component and associates it with the given entity. + * @param entity An Entity to associate a node component with. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(Entity e) was called. + * + * @see destroy() + */ + void create(Entity entity); + + /** + * Destroys this component from the given entity. + * @param e An entity. + * + * @see create() + */ + void destroy(Entity e) noexcept; + + void setMorphTargetNames(Instance ci, utils::FixedCapacityVector names) noexcept; + const utils::FixedCapacityVector& getMorphTargetNames(Instance ci) const noexcept; + + void setExtras(Instance ci, CString extras) noexcept; + const CString& getExtras(Instance ci) const noexcept; + + void setSceneMembership(Instance ci, SceneMask scenes) noexcept; + SceneMask getSceneMembership(Instance ci) const noexcept; + +protected: + NodeManager() noexcept = default; + ~NodeManager() = default; + +public: + NodeManager(NodeManager const&) = delete; + NodeManager(NodeManager&&) = delete; + NodeManager& operator=(NodeManager const&) = delete; + NodeManager& operator=(NodeManager&&) = delete; +}; + +} // namespace filament::gltfio + + +#endif // GLTFIO_NODEMANAGER_H diff --git a/package/android/libs/filament/include/gltfio/ResourceLoader.h b/package/android/libs/filament/include/gltfio/ResourceLoader.h new file mode 100644 index 00000000..05c8a56d --- /dev/null +++ b/package/android/libs/filament/include/gltfio/ResourceLoader.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef GLTFIO_RESOURCELOADER_H +#define GLTFIO_RESOURCELOADER_H + +#include + +#include + +#include + +namespace filament { + class Engine; +} + +namespace filament::gltfio { + +struct FFilamentAsset; +class AssetPool; +class TextureProvider; + +/** + * \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h + * \brief Construction parameters for ResourceLoader. + */ +struct ResourceConfiguration { + //! The engine that the loader should pass to builder objects (e.g. + //! filament::Texture::Builder). + class filament::Engine* engine; + + //! Optional path or URI that points to the base glTF file. This is used solely + //! to resolve relative paths. The string pointer is not retained. + const char* gltfPath; + + //! If true, adjusts skinning weights to sum to 1. Well formed glTF files do not need this, + //! but it is useful for robustness. + bool normalizeSkinningWeights; +}; + +/** + * \class ResourceLoader ResourceLoader.h gltfio/ResourceLoader.h + * \brief Prepares and uploads vertex buffers and textures to the GPU. + * + * For a usage example, see the documentation for AssetLoader. + * + * ResourceLoader must be destroyed on the same thread that calls filament::Renderer::render() + * because it listens to filament::backend::BufferDescriptor callbacks in order to determine when to + * free CPU-side data blobs. + * + * \todo If clients persist their ResourceLoader, Filament textures are currently re-created upon + * subsequent re-loads of the same asset. To fix this, we would need to enable shared ownership + * of Texture objects between ResourceLoader and FilamentAsset. + */ +class UTILS_PUBLIC ResourceLoader { +public: + using BufferDescriptor = filament::backend::BufferDescriptor; + + explicit ResourceLoader(const ResourceConfiguration& config); + ~ResourceLoader(); + + + void setConfiguration(const ResourceConfiguration& config); + + /** + * Feeds the binary content of an external resource into the loader's URI cache. + * + * On some platforms, `ResourceLoader` does not know how to download external resources on its + * own (external resources might come from a filesystem, a database, or the internet) so this + * method allows clients to download external resources and push them to the loader. + * + * Every resource should be passed in before calling #loadResources or #asyncBeginLoad. See + * also FilamentAsset#getResourceUris. + * + * When loading GLB files (as opposed to JSON-based glTF files), clients typically do not + * need to call this method. + */ + void addResourceData(const char* uri, BufferDescriptor&& buffer); + + /** + * Register a plugin that can consume PNG / JPEG content and produce filament::Texture objects. + * + * Destruction of the given provider is the client's responsibility. + */ + void addTextureProvider(const char* mimeType, TextureProvider* provider); + + /** + * Checks if the given resource has already been added to the URI cache. + */ + bool hasResourceData(const char* uri) const; + + /** + * Frees memory by evicting the URI cache that was populated via addResourceData. + * + * This can be called only after a model is fully loaded or after loading has been cancelled. + */ + void evictResourceData(); + + /** + * Loads resources for the given asset from the filesystem or data cache and "finalizes" the + * asset by transforming the vertex data format if necessary, decoding image files, supplying + * tangent data, etc. + * + * Returns false if resources have already been loaded, or if one or more resources could not + * be loaded. + * + * Note: this method is synchronous and blocks until all textures have been decoded. + * For an asynchronous alternative, see #asyncBeginLoad. + */ + bool loadResources(FilamentAsset* asset); + + /** + * Starts an asynchronous resource load. + * + * Returns false if the loading process was unable to start. + * + * This is an alternative to #loadResources and requires periodic calls to #asyncUpdateLoad. + * On multi-threaded systems this creates threads for texture decoding. + */ + bool asyncBeginLoad(FilamentAsset* asset); + + /** + * Gets the status of an asynchronous resource load as a percentage in [0,1]. + */ + float asyncGetLoadProgress() const; + + /** + * Updates an asynchronous load by performing any pending work that must take place + * on the main thread. + * + * Clients must periodically call this until #asyncGetLoadProgress returns 100%. + * After progress reaches 100%, calling this is harmless; it just does nothing. + */ + void asyncUpdateLoad(); + + /** + * Cancels pending decoder jobs, frees all CPU-side texel data, and flushes the Engine. + * + * Calling this is only necessary if the asyncBeginLoad API was used + * and cancellation is required before progress reaches 100%. + */ + void asyncCancelLoad(); + +private: + bool loadResources(FFilamentAsset* asset, bool async); + void normalizeSkinningWeights(FFilamentAsset* asset) const; + struct Impl; + Impl* pImpl; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_RESOURCELOADER_H + diff --git a/package/android/libs/filament/include/gltfio/TextureProvider.h b/package/android/libs/filament/include/gltfio/TextureProvider.h new file mode 100644 index 00000000..ff497af2 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/TextureProvider.h @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#ifndef GLTFIO_TEXTUREPROVIDER_H +#define GLTFIO_TEXTUREPROVIDER_H + +#include +#include + +#include +#include + +namespace filament { + class Engine; + class Texture; +} + +namespace filament::gltfio { + +/** + * TextureProvider is an interface that allows clients to implement their own texture decoding + * facility for JPEG, PNG, or KTX2 content. It constructs Filament Texture objects synchronously, + * but populates their miplevels asynchronously. + * + * gltfio calls all public methods from the foreground thread, i.e. the thread that the Filament + * engine was created with. However the implementation may create 0 or more background threads to + * perform decoding work. + * + * The following pseudocode illustrates how this interface could be used, but in practice the only + * client is the gltfio ResourceLoader. + * + * filament::Engine* engine = ...; + * TextureProvider* provider = createStbProvider(engine); + * + * for (auto filename : textureFiles) { + * std::vector buf = readEntireFile(filename); + * Texture* texture = provider->pushTexture(buf.data(), buf.size(), "image/png", 0); + * if (texture == nullptr) { puts(provider->getPushMessage()); exit(1); } + * } + * + * // At this point, the returned textures can be bound to material instances, but none of their + * // miplevel images have been populated yet. + * + * while (provider->getPoppedCount() < provider->getPushedCount()) { + * sleep(200); + * + * // The following call gives the provider an opportunity to reap the results of any + * // background decoder work that has been completed (e.g. by calling Texture::setImage). + * provider->updateQueue(); + * + * // Check for textures that now have all their miplevels initialized. + * while (Texture* texture = provider->popTexture()) { + * printf("%p has all its miplevels ready.\n", texture); + * } + * } + * + * delete provider; + */ +class UTILS_PUBLIC TextureProvider { +public: + using Texture = filament::Texture; + + enum class TextureFlags : uint64_t { + NONE = 0, + sRGB = 1 << 0, + }; + + /** + * Creates a Filament texture and pushes it to the asynchronous decoding queue. + * + * The provider synchronously determines the texture dimensions in order to create a Filament + * texture object, then populates the miplevels asynchronously. + * + * If construction fails, nothing is pushed to the queue and null is returned. The failure + * reason can be obtained with getPushMessage(). The given buffer pointer is not held, so the + * caller can free it immediately. It is also the caller's responsibility to free the returned + * Texture object, but it is only safe to do so after it has been popped from the queue. + */ + virtual Texture* pushTexture(const uint8_t* data, size_t byteCount, + const char* mimeType, TextureFlags flags) = 0; + + /** + * Checks if any texture is ready to be removed from the asynchronous decoding queue, and if so + * pops it off. + * + * Unless an error or cancellation occurred during the decoding process, the returned texture + * should have all its miplevels populated. If the texture is not complete, the reason can be + * obtained with getPopMessage(). + * + * Due to concurrency, textures are not necessarily popped off in the same order they were + * pushed. Returns null if there are no textures that are ready to be popped. + */ + virtual Texture* popTexture() = 0; + + /** + * Polls textures in the queue and uploads mipmap images if any have emerged from the decoder. + * + * This gives the provider an opportunity to call Texture::setImage() on the foreground thread. + * If needed, it can also call Texture::generateMipmaps() here. + * + * Items in the decoding queue can become "poppable" only during this call. + */ + virtual void updateQueue() = 0; + + /** + * Returns a failure message for the most recent call to pushTexture(), or null for success. + * + * Note that this method does not pertain to the decoding process. If decoding fails, clients to + * can pop the incomplete texture off the queue and obtain a failure message using the + * getPopFailure() method. + * + * The returned string is owned by the provider and becomes invalid after the next call to + * pushTexture(). + */ + virtual const char* getPushMessage() const = 0; + + /** + * Returns a failure message for the most recent call to popTexture(), or null for success. + * + * If the most recent call to popTexture() returned null, then no error occurred and this + * returns null. If the most recent call to popTexture() returned a "complete" texture (i.e. + * all miplevels present), then this returns null. This returns non-null only if an error or + * cancellation occurred while decoding the popped texture. + * + * The returned string is owned by the provider and becomes invalid after the next call to + * popTexture(). + */ + virtual const char* getPopMessage() const = 0; + + /** + * Waits for all outstanding decoding jobs to complete. + * + * Clients should call updateQueue() afterwards if they wish to update the push / pop queue. + */ + virtual void waitForCompletion() = 0; + + /** + * Cancels all not-yet-started decoding jobs and waits for all other jobs to complete. + * + * Jobs that have already started cannot be canceled. Textures whose decoding process has + * been cancelled will be made poppable on the subsequent call to updateQueue(). + */ + virtual void cancelDecoding() = 0; + + /** Total number of successful push calls since the provider was created. */ + virtual size_t getPushedCount() const = 0; + + /** Total number of successful pop calls since the provider was created. */ + virtual size_t getPoppedCount() const = 0; + + /** Total number of textures that have become ready-to-pop since the provider was created. */ + virtual size_t getDecodedCount() const = 0; + + virtual ~TextureProvider() = default; +}; + +/** + * Creates a simple decoder based on stb_image that can handle "image/png" and "image/jpeg". + * This works only if your build configuration includes STB. + */ +TextureProvider* createStbProvider(filament::Engine* engine); + +/** + * Creates a decoder that can handle certain types of "image/ktx2" content as specified in + * the KHR_texture_basisu specification. + */ +TextureProvider* createKtx2Provider(filament::Engine* engine); + +} // namespace filament::gltfio + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif // GLTFIO_TEXTUREPROVIDER_H diff --git a/package/android/libs/filament/include/gltfio/TrsTransformManager.h b/package/android/libs/filament/include/gltfio/TrsTransformManager.h new file mode 100644 index 00000000..980457b7 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/TrsTransformManager.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef GLTFIO_TRSTRANSFORMMANAGER_H +#define GLTFIO_TRSTRANSFORMMANAGER_H + +#include + +#include +#include +#include +#include +#include + +using namespace filament::math; + +namespace utils { +class Entity; +} // namespace utils + +namespace filament::gltfio { + +class FTrsTransformManager; + +/** + * TrsTransformManager is used to add entities with glTF-specific trs information. + * + * Trs information here just used for Animation, DON'T use for transform. + */ +class UTILS_PUBLIC TrsTransformManager { +public: + using Instance = utils::EntityInstance; + using Entity = utils::Entity; + + /** + * Returns whether a particular Entity is associated with a component of this TrsTransformManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(Entity e) const noexcept; + + /** + * Gets an Instance representing the trs transform component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the trs transform component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(Entity e) const noexcept; + + /** + * Creates a trs transform component and associates it with the given entity. + * @param entity An Entity to associate a trs transform component with. + * @param translation The translation to initialize the trs transform component with. + * @param rotation The rotation to initialize the trs transform component with. + * @param scale The scale to initialize the trs transform component with. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(Entity e) was called. + * + * @see destroy() + */ + void create(Entity entity); + void create(Entity entity, const float3& translation, const quatf& rotation, + const float3& scale); //!< \overload + + /** + * Destroys this component from the given entity. + * @param e An entity. + * + * @see create() + */ + void destroy(Entity e) noexcept; + + void setTranslation(Instance ci, const float3& translation) noexcept; + const float3& getTranslation(Instance ci) const noexcept; + + void setRotation(Instance ci, const quatf& rotation) noexcept; + const quatf& getRotation(Instance ci) const noexcept; + + void setScale(Instance ci, const float3& scale) noexcept; + const float3& getScale(Instance ci) const noexcept; + + void setTrs(Instance ci, const float3& translation, const quatf& rotation, + const float3& scale) noexcept; + const mat4f getTransform(Instance ci) const noexcept; + +protected: + TrsTransformManager() noexcept = default; + ~TrsTransformManager() = default; + +public: + TrsTransformManager(TrsTransformManager const&) = delete; + TrsTransformManager(TrsTransformManager&&) = delete; + TrsTransformManager& operator=(TrsTransformManager const&) = delete; + TrsTransformManager& operator=(TrsTransformManager&&) = delete; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_TRSTRANSFORMMANAGER_H diff --git a/package/android/libs/filament/include/gltfio/materials/uberarchive.h b/package/android/libs/filament/include/gltfio/materials/uberarchive.h new file mode 100644 index 00000000..b36ddd36 --- /dev/null +++ b/package/android/libs/filament/include/gltfio/materials/uberarchive.h @@ -0,0 +1,13 @@ +#ifndef UBERARCHIVE_H_ +#define UBERARCHIVE_H_ + +#include + +extern "C" { + extern const uint8_t UBERARCHIVE_PACKAGE[]; + extern int UBERARCHIVE_DEFAULT_OFFSET; + extern int UBERARCHIVE_DEFAULT_SIZE; +} +#define UBERARCHIVE_DEFAULT_DATA (UBERARCHIVE_PACKAGE + UBERARCHIVE_DEFAULT_OFFSET) + +#endif diff --git a/package/android/libs/filament/include/gltfio/math.h b/package/android/libs/filament/include/gltfio/math.h new file mode 100644 index 00000000..dfbe0fca --- /dev/null +++ b/package/android/libs/filament/include/gltfio/math.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_MATH_H +#define GLTFIO_MATH_H + +#include +#include +#include +#include +#include + +#include + +namespace filament::gltfio { + +template +UTILS_PUBLIC T cubicSpline(const T& vert0, const T& tang0, const T& vert1, const T& tang1, float t) { + float tt = t * t, ttt = tt * t; + float s2 = -2 * ttt + 3 * tt, s3 = ttt - tt; + float s0 = 1 - s2, s1 = s3 - tt + t; + T p0 = vert0; + T m0 = tang0; + T p1 = vert1; + T m1 = tang1; + return s0 * p0 + s1 * m0 * t + s2 * p1 + s3 * m1 * t; +} + +UTILS_PUBLIC inline void decomposeMatrix(const filament::math::mat4f& mat, filament::math::float3* translation, + filament::math::quatf* rotation, filament::math::float3* scale) { + using namespace filament::math; + + // Extract translation. + *translation = mat[3].xyz; + + // Extract upper-left for determinant computation. + const float a = mat[0][0]; + const float b = mat[0][1]; + const float c = mat[0][2]; + const float d = mat[1][0]; + const float e = mat[1][1]; + const float f = mat[1][2]; + const float g = mat[2][0]; + const float h = mat[2][1]; + const float i = mat[2][2]; + const float A = e * i - f * h; + const float B = f * g - d * i; + const float C = d * h - e * g; + + // Extract scale. + const float det(a * A + b * B + c * C); + float scalex = length(float3({a, b, c})); + float scaley = length(float3({d, e, f})); + float scalez = length(float3({g, h, i})); + float3 s = { scalex, scaley, scalez }; + if (det < 0) { + s = -s; + } + *scale = s; + + // Remove scale from the matrix if it is not close to zero. + mat4f clone = mat; + if (std::abs(det) > std::numeric_limits::epsilon()) { + clone[0] /= s.x; + clone[1] /= s.y; + clone[2] /= s.z; + // Extract rotation + *rotation = clone.toQuaternion(); + } else { + // Set to identity if close to zero + *rotation = quatf(1.0f); + } +} + +UTILS_PUBLIC inline filament::math::mat4f composeMatrix(const filament::math::float3& translation, + const filament::math::quatf& rotation, const filament::math::float3& scale) { + float tx = translation[0]; + float ty = translation[1]; + float tz = translation[2]; + float qx = rotation[0]; + float qy = rotation[1]; + float qz = rotation[2]; + float qw = rotation[3]; + float sx = scale[0]; + float sy = scale[1]; + float sz = scale[2]; + return filament::math::mat4f( + (1 - 2 * qy*qy - 2 * qz*qz) * sx, + (2 * qx*qy + 2 * qz*qw) * sx, + (2 * qx*qz - 2 * qy*qw) * sx, + 0.f, + (2 * qx*qy - 2 * qz*qw) * sy, + (1 - 2 * qx*qx - 2 * qz*qz) * sy, + (2 * qy*qz + 2 * qx*qw) * sy, + 0.f, + (2 * qx*qz + 2 * qy*qw) * sz, + (2 * qy*qz - 2 * qx*qw) * sz, + (1 - 2 * qx*qx - 2 * qy*qy) * sz, + 0.f, tx, ty, tz, 1.f); +} + +inline filament::math::mat3f matrixFromUvTransform(const float offset[2], float rotation, + const float scale[2]) { + float tx = offset[0]; + float ty = offset[1]; + float sx = scale[0]; + float sy = scale[1]; + float c = cos(rotation); + float s = sin(rotation); + return filament::math::mat3f(sx * c, sx * s, tx, -sy * s, sy * c, ty, 0.0f, 0.0f, 1.0f); +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_MATH_H diff --git a/package/android/libs/filament/include/ibl/Cubemap.h b/package/android/libs/filament/include/ibl/Cubemap.h new file mode 100644 index 00000000..2186bdb0 --- /dev/null +++ b/package/android/libs/filament/include/ibl/Cubemap.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAP_H +#define IBL_CUBEMAP_H + +#include + +#include + +#include +#include +#include + +#include + +namespace filament { +namespace ibl { + +/** + * Generic cubemap class. It handles writing / reading into the 6 faces of a cubemap. + * + * Seamless trilinear filtering is handled. + * + * This class doesn't own the face data, it's just a "view" on the 6 images. + * + * @see CubemapUtils + * + */ +class UTILS_PUBLIC Cubemap { +public: + + /** + * Initialize the cubemap with a given size, but no face is set and no memory is allocated. + * + * Usually Cubemaps are created using CubemapUtils. + * + * @see CubemapUtils + */ + explicit Cubemap(size_t dim); + + Cubemap(Cubemap&&) = default; + Cubemap& operator=(Cubemap&&) = default; + + ~Cubemap(); + + + enum class Face : uint8_t { + PX = 0, // left +----+ + NX, // right | PY | + PY, // bottom +----+----+----+----+ + NY, // top | NX | PZ | PX | NZ | + PZ, // back +----+----+----+----+ + NZ // front | NY | + // +----+ + }; + + using Texel = filament::math::float3; + + + //! releases all images and reset the cubemap size + void resetDimensions(size_t dim); + + //! assigns an image to a face. + void setImageForFace(Face face, const Image& image); + + //! retrieves the image attached to a face + inline const Image& getImageForFace(Face face) const; + + //! retrieves the image attached to a face + inline Image& getImageForFace(Face face); + + //! computes the center of a pixel at coordinate x, y + static inline filament::math::float2 center(size_t x, size_t y); + + //! computes a direction vector from a face and a location of the center of pixel in an Image + inline filament::math::float3 getDirectionFor(Face face, size_t x, size_t y) const; + + //! computes a direction vector from a face and a location in pixel in an Image + inline filament::math::float3 getDirectionFor(Face face, float x, float y) const; + + //! samples the cubemap at the given direction using nearest neighbor filtering + inline Texel const& sampleAt(const filament::math::float3& direction) const; + + //! samples the cubemap at the given direction using bilinear filtering + inline Texel filterAt(const filament::math::float3& direction) const; + + //! samples an image at the given location in pixel using bilinear filtering + static Texel filterAt(const Image& image, float x, float y); + static Texel filterAtCenter(const Image& image, size_t x, size_t y); + + //! samples two cubemaps in a given direction and lerps the result by a given lerp factor + static Texel trilinearFilterAt(const Cubemap& c0, const Cubemap& c1, float lerp, + const filament::math::float3& direction); + + //! reads a texel at a given address + inline static const Texel& sampleAt(void const* data) { + return *static_cast(data); + } + + //! writes a texel at a given address + inline static void writeAt(void* data, const Texel& texel) { + *static_cast(data) = texel; + } + + //! returns the size of the cubemap in pixels + size_t getDimensions() const; + + /** + * Prepares a cubemap for seamless access to its faces. + * + * @warning All faces of the cubemap must be backed-up by the same Image, and must already + * be spaced by 2 lines/rows. + */ + void makeSeamless(); + + struct Address { + Face face; + float s = 0; + float t = 0; + }; + + //! returns the face and texture coordinates of the given direction + static Address getAddressFor(const filament::math::float3& direction); + +private: + size_t mDimensions = 0; + float mScale = 1; + float mUpperBound = 0; + Image mFaces[6]; +}; + +// ------------------------------------------------------------------------------------------------ + +inline const Image& Cubemap::getImageForFace(Face face) const { + return mFaces[int(face)]; +} + +inline Image& Cubemap::getImageForFace(Face face) { + return mFaces[int(face)]; +} + +inline filament::math::float2 Cubemap::center(size_t x, size_t y) { + return { x + 0.5f, y + 0.5f }; +} + +inline filament::math::float3 Cubemap::getDirectionFor(Face face, size_t x, size_t y) const { + return getDirectionFor(face, x + 0.5f, y + 0.5f); +} + +inline filament::math::float3 Cubemap::getDirectionFor(Face face, float x, float y) const { + // map [0, dim] to [-1,1] with (-1,-1) at bottom left + float cx = (x * mScale) - 1; + float cy = 1 - (y * mScale); + + filament::math::float3 dir; + const float l = std::sqrt(cx * cx + cy * cy + 1); + switch (face) { + case Face::PX: dir = { 1, cy, -cx }; break; + case Face::NX: dir = { -1, cy, cx }; break; + case Face::PY: dir = { cx, 1, -cy }; break; + case Face::NY: dir = { cx, -1, cy }; break; + case Face::PZ: dir = { cx, cy, 1 }; break; + case Face::NZ: dir = { -cx, cy, -1 }; break; + } + return dir * (1 / l); +} + +inline Cubemap::Texel const& Cubemap::sampleAt(const filament::math::float3& direction) const { + Cubemap::Address addr(getAddressFor(direction)); + const size_t x = std::min(size_t(addr.s * mDimensions), mDimensions - 1); + const size_t y = std::min(size_t(addr.t * mDimensions), mDimensions - 1); + return sampleAt(getImageForFace(addr.face).getPixelRef(x, y)); +} + +inline Cubemap::Texel Cubemap::filterAt(const filament::math::float3& direction) const { + Cubemap::Address addr(getAddressFor(direction)); + addr.s = std::min(addr.s * mDimensions, mUpperBound); + addr.t = std::min(addr.t * mDimensions, mUpperBound); + return filterAt(getImageForFace(addr.face), addr.s, addr.t); +} + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAP_H */ diff --git a/package/android/libs/filament/include/ibl/CubemapIBL.h b/package/android/libs/filament/include/ibl/CubemapIBL.h new file mode 100644 index 00000000..925e27c0 --- /dev/null +++ b/package/android/libs/filament/include/ibl/CubemapIBL.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAPIBL_H +#define IBL_CUBEMAPIBL_H + +#include + +#include +#include + +#include + +#include +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class Cubemap; +class Image; + +/** + * Generates cubemaps for the IBL. + */ +class UTILS_PUBLIC CubemapIBL { +public: + typedef void (*Progress)(size_t, float, void*); + + /** + * Computes a roughness LOD using prefiltered importance sampling GGX + * + * @param dst the destination cubemap + * @param levels a list of prefiltered lods of the source environment + * @param linearRoughness roughness + * @param maxNumSamples number of samples for importance sampling + * @param updater a callback for the caller to track progress + */ + static void roughnessFilter( + utils::JobSystem& js, Cubemap& dst, const utils::Slice& levels, + float linearRoughness, size_t maxNumSamples, math::float3 mirror, bool prefilter, + Progress updater = nullptr, void* userdata = nullptr); + + static void roughnessFilter( + utils::JobSystem& js, Cubemap& dst, const std::vector& levels, + float linearRoughness, size_t maxNumSamples, math::float3 mirror, bool prefilter, + Progress updater = nullptr, void* userdata = nullptr); + + //! Computes the "DFG" term of the "split-sum" approximation and stores it in a 2D image + static void DFG(utils::JobSystem& js, Image& dst, bool multiscatter, bool cloth); + + /** + * Computes the diffuse irradiance using prefiltered importance sampling GGX + * + * @note Usually this is done using spherical harmonics instead. + * + * @param dst the destination cubemap + * @param levels a list of prefiltered lods of the source environment + * @param maxNumSamples number of samples for importance sampling + * @param updater a callback for the caller to track progress + * + * @see CubemapSH + */ + static void diffuseIrradiance(utils::JobSystem& js, Cubemap& dst, const std::vector& levels, + size_t maxNumSamples = 1024, Progress updater = nullptr, void* userdata = nullptr); + + // for debugging. ignore. + static void brdf(utils::JobSystem& js, Cubemap& dst, float linearRoughness); +}; + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAPIBL_H */ diff --git a/package/android/libs/filament/include/ibl/CubemapSH.h b/package/android/libs/filament/include/ibl/CubemapSH.h new file mode 100644 index 00000000..b9297c74 --- /dev/null +++ b/package/android/libs/filament/include/ibl/CubemapSH.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAPSH_H +#define IBL_CUBEMAPSH_H + + +#include + +#include +#include + +#include +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class Cubemap; + +/** + * Computes spherical harmonics + */ +class UTILS_PUBLIC CubemapSH { +public: + /** + * Spherical Harmonics decomposition of the given cubemap + * Optionally calculates irradiance by convolving with truncated cos. + */ + static std::unique_ptr computeSH( + utils::JobSystem& js, const Cubemap& cm, size_t numBands, bool irradiance); + + /** + * Render given spherical harmonics into a cubemap + */ + static void renderSH(utils::JobSystem& js, Cubemap& cm, + const std::unique_ptr& sh, size_t numBands); + + static void windowSH(std::unique_ptr& sh, size_t numBands, float cutoff); + + /** + * Compute spherical harmonics of the irradiance of the given cubemap. + * The SH basis are pre-scaled for easier rendering by the shader. The resulting coefficients + * are not spherical harmonics (as they're scalled by various factors). In particular they + * cannot be rendered with renderSH() above. Instead use renderPreScaledSH3Bands() which + * is exactly the code ran by our shader. + */ + static void preprocessSHForShader(std::unique_ptr& sh); + + /** + * Render pre-scaled irrandiance SH + */ + static void renderPreScaledSH3Bands(utils::JobSystem& js, Cubemap& cm, + const std::unique_ptr& sh); + + static constexpr size_t getShIndex(ssize_t m, size_t l) { + return SHindex(m, l); + } + +private: + class float5 { + float v[5]; + public: + float5() = default; + constexpr float5(float a, float b, float c, float d, float e) : v{ a, b, c, d, e } {} + constexpr float operator[](size_t i) const { return v[i]; } + float& operator[](size_t i) { return v[i]; } + }; + + static inline const float5 multiply(const float5 M[5], float5 x) noexcept { + return float5{ + M[0][0] * x[0] + M[1][0] * x[1] + M[2][0] * x[2] + M[3][0] * x[3] + M[4][0] * x[4], + M[0][1] * x[0] + M[1][1] * x[1] + M[2][1] * x[2] + M[3][1] * x[3] + M[4][1] * x[4], + M[0][2] * x[0] + M[1][2] * x[1] + M[2][2] * x[2] + M[3][2] * x[3] + M[4][2] * x[4], + M[0][3] * x[0] + M[1][3] * x[1] + M[2][3] * x[2] + M[3][3] * x[3] + M[4][3] * x[4], + M[0][4] * x[0] + M[1][4] * x[1] + M[2][4] * x[2] + M[3][4] * x[3] + M[4][4] * x[4] + }; + }; + + + static inline constexpr size_t SHindex(ssize_t m, size_t l) { + return l * (l + 1) + m; + } + + static void computeShBasis(float* SHb, size_t numBands, const math::float3& s); + + static float Kml(ssize_t m, size_t l); + + static std::vector Ki(size_t numBands); + + static constexpr float computeTruncatedCosSh(size_t l); + + static float sincWindow(size_t l, float w); + + static math::float3 rotateShericalHarmonicBand1(math::float3 band1, math::mat3f const& M); + + static float5 rotateShericalHarmonicBand2(float5 const& band2, math::mat3f const& M); + + // debugging only... + static float Legendre(ssize_t l, ssize_t m, float x); + static float TSH(int l, int m, const math::float3& d); + static void printShBase(std::ostream& out, int l, int m); +}; + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAPSH_H */ diff --git a/package/android/libs/filament/include/ibl/CubemapUtils.h b/package/android/libs/filament/include/ibl/CubemapUtils.h new file mode 100644 index 00000000..3b4a3154 --- /dev/null +++ b/package/android/libs/filament/include/ibl/CubemapUtils.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAP_UTILS_H +#define IBL_CUBEMAP_UTILS_H + +#include +#include + +#include + +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class CubemapIBL; + +/** + * Create and convert Cubemap formats + */ +class UTILS_PUBLIC CubemapUtils { +public: + //! Creates a cubemap object and its backing Image + static Cubemap create(Image& image, size_t dim, bool horizontal = true); + + struct EmptyState { + }; + + template + using ScanlineProc = std::function< + void(STATE& state, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t width)>; + + template + using ReduceProc = std::function; + + //! process the cubemap using multithreading + template + static void process(Cubemap& cm, + utils::JobSystem& js, + ScanlineProc proc, + ReduceProc reduce = [](STATE&) {}, + const STATE& prototype = STATE()); + + //! process the cubemap + template + static void processSingleThreaded(Cubemap& cm, + utils::JobSystem& js, + ScanlineProc proc, + ReduceProc reduce = [](STATE&) {}, + const STATE& prototype = STATE()); + + //! clamps image to acceptable range + static void clamp(Image& src); + + static void highlight(Image& src); + + //! Downsamples a cubemap by helf in x and y using a box filter + static void downsampleCubemapLevelBoxFilter(utils::JobSystem& js, Cubemap& dst, const Cubemap& src); + + //! Return the name of a face (suitable for a file name) + static const char* getFaceName(Cubemap::Face face); + + //! computes the solid angle of a pixel of a face of a cubemap + static float solidAngle(size_t dim, size_t u, size_t v); + + //! Sets a Cubemap faces from a cross image + static void setAllFacesFromCross(Cubemap& cm, const Image& image); + +private: + + //move these into cmgen? + static void setFaceFromCross(Cubemap& cm, Cubemap::Face face, const Image& image); + static Image createCubemapImage(size_t dim, bool horizontal = true); + +#ifndef FILAMENT_IBL_LITE + +public: + + //! Converts horizontal or vertical cross Image to a Cubemap + static void crossToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src); + + //! Converts equirectangular Image to a Cubemap + static void equirectangularToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src); + + //! Converts a Cubemap to an equirectangular Image + static void cubemapToEquirectangular(utils::JobSystem& js, Image& dst, const Cubemap& src); + + //! Converts a Cubemap to an octahedron + static void cubemapToOctahedron(utils::JobSystem& js, Image& dst, const Cubemap& src); + + //! mirror the cubemap in the horizontal direction + static void mirrorCubemap(utils::JobSystem& js, Cubemap& dst, const Cubemap& src); + + //! generates a UV grid in the cubemap -- useful for debugging. + static void generateUVGrid(utils::JobSystem& js, Cubemap& cml, size_t gridFrequencyX, size_t gridFrequencyY); + +#endif + + friend class CubemapIBL; +}; + + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAP_UTILS_H */ diff --git a/package/android/libs/filament/include/ibl/Image.h b/package/android/libs/filament/include/ibl/Image.h new file mode 100644 index 00000000..1ebaa62b --- /dev/null +++ b/package/android/libs/filament/include/ibl/Image.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_IMAGE_H +#define IBL_IMAGE_H + +#include +#include +#include + +#include + +#include + +namespace filament { +namespace ibl { + +class UTILS_PUBLIC Image { +public: + Image(); + Image(size_t w, size_t h, size_t stride = 0); + + void reset(); + + void set(Image const& image); + + void subset(Image const& image, size_t x, size_t y, size_t w, size_t h); + + bool isValid() const { return mData != nullptr; } + + size_t getWidth() const { return mWidth; } + + size_t getStride() const { return mBpr / getBytesPerPixel(); } + + size_t getHeight() const { return mHeight; } + + size_t getBytesPerRow() const { return mBpr; } + + size_t getBytesPerPixel() const { return sizeof(math::float3); } + + void* getData() const { return mData; } + + size_t getSize() const { return mBpr * mHeight; } + + void* getPixelRef(size_t x, size_t y) const; + + std::unique_ptr detach() { return std::move(mOwnedData); } + +private: + size_t mBpr = 0; + size_t mWidth = 0; + size_t mHeight = 0; + std::unique_ptr mOwnedData; + void* mData = nullptr; +}; + +inline void* Image::getPixelRef(size_t x, size_t y) const { + return static_cast(mData) + y * getBytesPerRow() + x * getBytesPerPixel(); +} + +} // namespace ibl +} // namespace filament + +#endif /* IBL_IMAGE_H */ diff --git a/package/android/libs/filament/include/ibl/utilities.h b/package/android/libs/filament/include/ibl/utilities.h new file mode 100644 index 00000000..6d40cc03 --- /dev/null +++ b/package/android/libs/filament/include/ibl/utilities.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_UTILITIES_H +#define IBL_UTILITIES_H + +#include + +#include +#include + +namespace filament { +namespace ibl { + +template +static inline constexpr T sq(T x) { + return x * x; +} + +template +static inline constexpr T log4(T x) { + // log2(x)/log2(4) + // log2(x)/2 + return std::log2(x) * T(0.5); +} + +inline bool isPOT(size_t x) { + return !(x & (x - 1)); +} + +inline filament::math::float2 hammersley(uint32_t i, float iN) { + constexpr float tof = 0.5f / 0x80000000U; + uint32_t bits = i; + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return { i * iN, bits * tof }; +} + +} // namespace ibl +} // namespace filament +#endif /* IBL_UTILITIES_H */ diff --git a/package/android/libs/filament/include/image/ColorTransform.h b/package/android/libs/filament/include/image/ColorTransform.h new file mode 100644 index 00000000..f5f8f195 --- /dev/null +++ b/package/android/libs/filament/include/image/ColorTransform.h @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_COLORTRANSFORM_H_ +#define IMAGE_COLORTRANSFORM_H_ + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace image { + +template +uint32_t linearToRGB_10_11_11_REV(const T& linear) { + using fp11 = filament::math::fp<0, 5, 6>; + using fp10 = filament::math::fp<0, 5, 5>; + // the max value for a RGB_11_11_10 is {65024, 65024, 64512} : (2 - 2^-M) * 2^(E-1) + // we clamp to the min of that + fp11 r = fp11::fromf(std::min(64512.0f, linear[0])); + fp11 g = fp11::fromf(std::min(64512.0f, linear[1])); + fp10 b = fp10::fromf(std::min(64512.0f, linear[2])); + uint32_t ir = r.bits & 0x7FF; + uint32_t ig = g.bits & 0x7FF; + uint32_t ib = b.bits & 0x3FF; + return (ib << 22) | (ig << 11) | ir; +} + +template +inline filament::math::float4 linearToRGBM(const T& linear) { + using filament::math::float4; + + float4 RGBM(linear[0], linear[1], linear[2], 1.0f); + + // Linear to gamma space + RGBM.rgb = sqrt(RGBM.rgb); + // Set the range + RGBM.rgb /= 16.0f; + + float maxComponent = std::max(std::max(RGBM.r, RGBM.g), std::max(RGBM.b, 1e-6f)); + // Don't let M go below 1 in the [0..16] range + RGBM.a = filament::math::clamp(maxComponent, 1.0f / 16.0f, 1.0f); + RGBM.a = std::ceil(RGBM.a * 255.0f) / 255.0f; + + RGBM.rgb = saturate(RGBM.rgb / RGBM.a); + + return RGBM; +} + +template +inline filament::math::float3 RGBMtoLinear(const T& rgbm) { + using filament::math::float3; + + float3 linear(rgbm[0], rgbm[1], rgbm[2]); + linear *= rgbm.a * 16.0f; + // Gamma to linear space + return linear * linear; +} + +template +inline filament::math::float3 linearTosRGB(const T& linear) { + using filament::math::float3; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 1 / 2.4f; + float3 sRGB; + for (size_t i=0 ; i<3 ; i++) { + if (linear[i] <= 0.0031308f) { + sRGB[i] = linear[i] * 12.92f; + } else { + sRGB[i] = a1 * std::pow(linear[i], p) - a; + } + } + return sRGB; +} + +inline float linearTosRGB(float linear) { + if (linear <= 0.0031308f) { + return linear * 12.92f; + } else { + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 1 / 2.4f; + return a1 * std::pow(linear, p) - a; + } +} + +template +T sRGBToLinear(const T& sRGB); + +template<> +inline filament::math::float3 sRGBToLinear(const filament::math::float3& sRGB) { + using filament::math::float3; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 2.4f; + float3 linear; + for (size_t i=0 ; i<3 ; i++) { + if (sRGB[i] <= 0.04045f) { + linear[i] = sRGB[i] * (1.0f / 12.92f); + } else { + linear[i] = std::pow((sRGB[i] + a) / a1, p); + } + } + return linear; +} + +template<> +inline filament::math::float4 sRGBToLinear(const filament::math::float4& sRGB) { + using filament::math::float4; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 2.4f; + float4 linear; + for (size_t i=0 ; i<3 ; i++) { + if (sRGB[i] <= 0.04045f) { + linear[i] = sRGB[i] * (1.0f / 12.92f); + } else { + linear[i] = std::pow((sRGB[i] + a) / a1, p); + } + } + linear[3] = sRGB[3]; + return linear; +} + +template +T linearToSRGB(const T& color); + +template<> +inline filament::math::float3 linearToSRGB(const filament::math::float3& color) { + using filament::math::float3; + float3 sRGBColor{color}; + UTILS_NOUNROLL + for (size_t i = 0; i < sRGBColor.size(); i++) { + sRGBColor[i] = (sRGBColor[i] <= 0.0031308f) ? + sRGBColor[i] * 12.92f : (powf(sRGBColor[i], 1.0f / 2.4f) * 1.055f) - 0.055f; + } + return sRGBColor; +} + +// Creates a N-channel sRGB image from a linear floating-point image. +// The source image can have more than N channels, but only the first 3 are converted to sRGB. +template +std::unique_ptr fromLinearTosRGB(const LinearImage& image) { + const size_t w = image.getWidth(); + const size_t h = image.getHeight(); + const size_t nchan = image.getChannels(); + assert(nchan >= N); + std::unique_ptr dst(new uint8_t[w * h * N * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, p += nchan, d += N) { + for (int n = 0; n < N; n++) { + float source = n < 3 ? linearTosRGB(p[n]) : p[n]; + float target = filament::math::saturate(source) * std::numeric_limits::max() + 0.5f; + d[n] = T(target); + } + } + } + return dst; +} + +// Creates a N-channel RGB u8 image from a f32 image. +template +std::unique_ptr fromLinearToRGB(const LinearImage& image) { + size_t w = image.getWidth(); + size_t h = image.getHeight(); + size_t channels = image.getChannels(); + assert(channels >= N); + std::unique_ptr dst(new uint8_t[w * h * N * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, p += channels, d += N) { + for (int n = 0; n < N; n++) { + float target = filament::math::saturate(p[n]) * std::numeric_limits::max() + 0.5f; + d[n] = T(target); + } + } + } + return dst; +} + +// Creates a 4-channel RGBM u8 image from a f32 image. +// The source image can have three or more channels, but only the first three are honored. +template +std::unique_ptr fromLinearToRGBM(const LinearImage& image) { + using namespace filament::math; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + UTILS_UNUSED_IN_RELEASE size_t channels = image.getChannels(); + assert(channels >= 3); + std::unique_ptr dst(new uint8_t[w * h * 4 * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + for (size_t x = 0; x < w; ++x, d += 4) { + auto src = image.get((uint32_t) x, (uint32_t) y); + float4 l(linearToRGBM(*src) * std::numeric_limits::max() + 0.5f); + for (size_t i = 0; i < 4; i++) { + d[i] = T(l[i]); + } + } + } + return dst; +} + +// Creates a 3-channel RGB_10_11_11_REV image from a f32 image. +// The source image can have three or more channels, but only the first three are honored. +inline std::unique_ptr fromLinearToRGB_10_11_11_REV(const LinearImage& image) { + using namespace filament::math; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + UTILS_UNUSED_IN_RELEASE size_t channels = image.getChannels(); + assert(channels >= 3); + std::unique_ptr dst(new uint8_t[w * h * sizeof(uint32_t)]); + uint8_t* d = dst.get(); + for (size_t y = 0; y < h; ++y) { + for (size_t x = 0; x < w; ++x, d += sizeof(uint32_t)) { + auto src = image.get((uint32_t)x, (uint32_t)y); + uint32_t v = linearToRGB_10_11_11_REV(*src); + *reinterpret_cast(d) = v; + } + } + return dst; +} + +// Creates a packed single-channel integer-based image from a floating-point image. +// For example if T is uint8_t, then this performs a transformation from [0,1] to [0,255]. +template +std::unique_ptr fromLinearToGrayscale(const LinearImage& image) { + const size_t w = image.getWidth(); + const size_t h = image.getHeight(); + assert(image.getChannels() == 1); + std::unique_ptr dst(new uint8_t[w * h * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, ++p, ++d) { + const float gray = filament::math::saturate(*p) * std::numeric_limits::max() + 0.5f; + d[0] = T(gray); + } + } + return dst; +} + +// Constructs a 3-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// The "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, + const uint8_t* src, PROCESS proc, TRANSFORM transform) { + LinearImage result((uint32_t) w, (uint32_t) h, 3); + auto d = result.get< filament::math::float3>(); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 3) { + filament::math::float3 sRGB(proc(p[0]), proc(p[1]), proc(p[2])); + sRGB /= std::numeric_limits::max(); + *d++ = transform(sRGB); + } + } + return result; +} + +// Constructs a 3-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// The "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, + const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { + return toLinear(w, h, bpr, src.get(), proc, transform); +} + +// Constructs a 4-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// the "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, + const uint8_t* src, PROCESS proc, TRANSFORM transform) { + LinearImage result((uint32_t) w, (uint32_t) h, 4); + auto d = result.get< filament::math::float4>(); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 4) { + filament::math::float4 sRGB(proc(p[0]), proc(p[1]), proc(p[2]), proc(p[3])); + sRGB /= std::numeric_limits::max(); + *d++ = transform(sRGB); + } + } + return result; +} + +// Constructs a 4-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// the "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, + const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { + return toLinearWithAlpha(w, h, bpr, src.get(), proc, transform); +} + +// Constructs a 3-channel LinearImage from RGBM data. +inline LinearImage toLinearFromRGBM( filament::math::float4 const* src, uint32_t w, uint32_t h) { + LinearImage result(w, h, 3); + auto dst = result.get< filament::math::float3>(); + for (uint32_t row = 0; row < h; ++row) { + for (uint32_t col = 0; col < w; ++col, ++src, ++dst) { + *dst = RGBMtoLinear(*src); + } + } + return result; +} + +inline LinearImage fromLinearToRGBM(const LinearImage& image) { + assert(image.getChannels() == 3); + const uint32_t w = image.getWidth(), h = image.getHeight(); + LinearImage result(w, h, 4); + auto src = image.get< filament::math::float3>(); + auto dst = result.get< filament::math::float4>(); + for (uint32_t row = 0; row < h; ++row) { + for (uint32_t col = 0; col < w; ++col, ++src, ++dst) { + *dst = linearToRGBM(*src); + } + } + return result; +} + +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, const uint8_t* src) { + LinearImage result(w, h, 4); + filament::math::float4* d = reinterpret_cast(result.getPixelRef(0, 0)); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 4) { + filament::math::float3 sRGB(p[0], p[1], p[2]); + sRGB /= std::numeric_limits::max(); + *d++ = filament::math::float4(sRGBToLinear(sRGB), 1.0f); + } + } + return result; +} + +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, const uint8_t* src) { + LinearImage result(w, h, 3); + filament::math::float3* d = reinterpret_cast(result.getPixelRef(0, 0)); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 3) { + filament::math::float3 sRGB(p[0], p[1], p[2]); + sRGB /= std::numeric_limits::max(); + *d++ = sRGBToLinear(sRGB); + } + } + return result; +} + +} // namespace Image + +#endif // IMAGE_COLORTRANSFORM_H_ diff --git a/package/android/libs/filament/include/image/ImageOps.h b/package/android/libs/filament/include/image/ImageOps.h new file mode 100644 index 00000000..50adc90e --- /dev/null +++ b/package/android/libs/filament/include/image/ImageOps.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_IMAGEOPS_H +#define IMAGE_IMAGEOPS_H + +#include + +#include + +#include +#include + +namespace image { + +// Concatenates images horizontally to create a filmstrip atlas, similar to numpy's hstack. +UTILS_PUBLIC LinearImage horizontalStack(std::initializer_list images); +UTILS_PUBLIC LinearImage horizontalStack(LinearImage const* img, size_t count); + +// Concatenates images vertically to create a filmstrip atlas, similar to numpy's vstack. +UTILS_PUBLIC LinearImage verticalStack(std::initializer_list images); +UTILS_PUBLIC LinearImage verticalStack(LinearImage const* img, size_t count); + +// Horizontally or vertically mirror the given image. +UTILS_PUBLIC LinearImage horizontalFlip(const LinearImage& image); +UTILS_PUBLIC LinearImage verticalFlip(const LinearImage& image); + +// Transforms normals (components live in [-1,+1]) into colors (components live in [0,+1]). +UTILS_PUBLIC LinearImage vectorsToColors(const LinearImage& image); +UTILS_PUBLIC LinearImage colorsToVectors(const LinearImage& image); + +// Creates a single-channel image by extracting the selected channel. +UTILS_PUBLIC LinearImage extractChannel(const LinearImage& image, uint32_t channel); + +// Constructs a multi-channel image by copying data from a sequence of single-channel images. +UTILS_PUBLIC LinearImage combineChannels(std::initializer_list images); +UTILS_PUBLIC LinearImage combineChannels(LinearImage const* img, size_t count); + +// Generates a new image with rows & columns swapped. +UTILS_PUBLIC LinearImage transpose(const LinearImage& image); + +// Extracts pixels by specifying a crop window where (0,0) is the top-left corner of the image. +// The boundary is specified as Left Top Right Bottom. +UTILS_PUBLIC +LinearImage cropRegion(const LinearImage& image, uint32_t l, uint32_t t, uint32_t r, uint32_t b); + +// Lexicographically compares two images, similar to memcmp. +UTILS_PUBLIC int compare(const LinearImage& a, const LinearImage& b, float epsilon = 0.0f); + +// Sets all pixels in all channels to the given value. +UTILS_PUBLIC void clearToValue(LinearImage& img, float value); + +// Called by the coordinate field generator to query if a pixel is within the region of interest. +using PresenceCallback = bool(*)(const LinearImage& img, uint32_t col, uint32_t row, void* user); + +// Generates a two-channel field of non-normalized coordinates that indicate the nearest pixel +// whose presence function returns true. This is the first step before generating a distance +// field or generalized Voronoi map. +UTILS_PUBLIC +LinearImage computeCoordField(const LinearImage& src, PresenceCallback presence, void* user); + +// Generates a single-channel Euclidean distance field with positive values outside the region +// of interest in the source image, and zero values inside. If sqrt is false, the computed +// distances are squared. If signed distance (SDF) is desired, this function can be called a second +// time using an inverted source field. +UTILS_PUBLIC LinearImage edtFromCoordField(const LinearImage& coordField, bool sqrt); + +// Dereferences the given coordinate field. Useful for creating Voronoi diagrams or dilated images. +UTILS_PUBLIC +LinearImage voronoiFromCoordField(const LinearImage& coordField, const LinearImage& src); + +// Copies content of a source image into a target image. Requires width/height/channels to match. +UTILS_PUBLIC void blitImage(LinearImage& target, const LinearImage& source); + +} // namespace image + + +#endif /* IMAGE_LINEARIMAGE_H */ diff --git a/package/android/libs/filament/include/image/ImageSampler.h b/package/android/libs/filament/include/image/ImageSampler.h new file mode 100644 index 00000000..e01da45e --- /dev/null +++ b/package/android/libs/filament/include/image/ImageSampler.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_IMAGESAMPLER_H +#define IMAGE_IMAGESAMPLER_H + +#include + +#include + +namespace image { + +/** + * Value of a single point sample, allocated according to the number of image channels. + */ +struct UTILS_PUBLIC SingleSample { + float& operator[](int index) { return *(data + index); } + float* data = nullptr; + ~SingleSample(); +}; + +/** + * Controls the weighted average used across a window of source samples. + */ +enum class Filter { + DEFAULT, // Selects MITCHELL or LANCZOS dynamically. + BOX, // Computes the un-weighted average over the filter radius. + NEAREST, // Copies the source sample nearest to the center of the filter. + HERMITE, // Also known as "smoothstep", has some nice properties. + GAUSSIAN_SCALARS, // Standard Gaussian filter with sigma = 0.5 + GAUSSIAN_NORMALS, // Same as GAUSSIAN_SCALARS, but interpolates unitized vectors. + MITCHELL, // Cubic resampling per Mitchell-Netravali, default for magnification. + LANCZOS, // Popular sinc-based filter, default for minification. + MINIMUM // Takes a min val rather than avg, perhaps useful for depth maps and SDF's. +}; + +/** + * Defines a viewport inside the texture such that (0,0) is at the top-left corner of the top-left + * pixel, and (1,1) is at the bottom-right corner of the bottom-corner pixel. + */ +struct Region { + float left; + float top; + float right; + float bottom; +}; + +/** + * Transforms the texel fetching operation when sampling from adjacent images. + */ +enum class Orientation { + STANDARD = 0, + FLIP_X = 1 << 0, + FLIP_Y = 1 << 1, + FLIP_XY = FLIP_X | FLIP_Y +}; + +/** + * Specifies how to generate samples that lie outside the boundaries of the source region. + */ +struct Boundary { + enum { + EXCLUDE, // Ignore the samples and renormalize the filter. This is probably what you want. + REGION, // Keep samples that are outside sourceRegion if they are still within the image. + CLAMP, // Pretend the edge pixel is repeated forever. Gives edge pixels more weight. + REPEAT, // Resample from the region, wrapping back to the front of the row or column. + MIRROR, // Resample from the region but assume that it has been flipped. + COLOR, // Use the specified constant color. + NEIGHBOR // Sample from an adjacent image. + } mode = EXCLUDE; + SingleSample color; // Used only if mode = COLOR + LinearImage* neighbor = nullptr; // Used only if mode = NEIGHBOR + Orientation orientation; // Used only if mode = NEIGHBOR +}; + +/** + * Configuration for the resampleImage function. Provides reasonable defaults. + */ +struct ImageSampler { + Filter horizontalFilter = Filter::DEFAULT; + Filter verticalFilter = Filter::DEFAULT; + Region sourceRegion = {0, 0, 1, 1}; + float filterRadiusMultiplier = 1; + Boundary east; + Boundary north; + Boundary west; + Boundary south; +}; + +/** + * Resizes or blurs the given linear image, producing a new linear image with the given dimensions. + */ +UTILS_PUBLIC +LinearImage resampleImage(const LinearImage& source, uint32_t width, uint32_t height, + const ImageSampler& sampler); + +/** + * Resizes the given linear image using a simplified API that takes target dimensions and filter. + */ +UTILS_PUBLIC +LinearImage resampleImage(const LinearImage& source, uint32_t width, uint32_t height, + Filter filter = Filter::DEFAULT); + +/** + * Computes a single sample for the given texture coordinate and writes the resulting color + * components into the given output holder. + * + * For decent performance, do not call this across the entire image, instead call resampleImage. + * On the first call, pass in a default SingleSample to allocate the result holder. For example: + * + * SingleSample result; + * computeSingleSample(img, 0.5f, 0.5f, &result); + * printf("r g b = %f %f %f\n", result[0], result[1], result[2]); + * computeSingleSample(img, 0.9f, 0.1f, &result); + * printf("r g b = %f %f %f\n", result[0], result[1], result[2]); + * + * The x y coordinates live in "texture space" such that (0.0f, 0.0f) is the upper-left boundary of + * the top-left pixel and (+1.0f, +1.0f) is the lower-right boundary of the bottom-right pixel. + */ +UTILS_PUBLIC +void computeSingleSample(const LinearImage& source, float x, float y, SingleSample* result, + Filter filter = Filter::BOX); + +/** + * Generates a sequence of miplevels using the requested filter. To determine the number of mips + * it would take to get down to 1x1, see getMipmapCount. + * + * Source image need not be power-of-two. In the result vector, the half-size image is returned at + * index 0, the quarter-size image is at index 1, etc. Please note that the original-sized image is + * not included. + */ +UTILS_PUBLIC +void generateMipmaps(const LinearImage& source, Filter, LinearImage* result, uint32_t mipCount); + +/** + * Returns the number of miplevels it would take to downsample the given image down to 1x1. This + * number does not include the original image (i.e. mip 0). + */ +UTILS_PUBLIC +uint32_t getMipmapCount(const LinearImage& source); + +/** + * Given the string name of a filter, converts it to uppercase and returns the corresponding + * enum value. If no corresponding enumerant exists, returns DEFAULT. + */ +UTILS_PUBLIC +Filter filterFromString(const char* name); + +} // namespace image + +#endif /* IMAGE_IMAGESAMPLER_H */ diff --git a/package/android/libs/filament/include/image/Ktx1Bundle.h b/package/android/libs/filament/include/image/Ktx1Bundle.h new file mode 100644 index 00000000..430f92be --- /dev/null +++ b/package/android/libs/filament/include/image/Ktx1Bundle.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_KTX1BUNDLE_H +#define IMAGE_KTX1BUNDLE_H + +#include + +#include + +#include +#include + +namespace image { + +struct KtxInfo { + uint32_t endianness; + uint32_t glType; + uint32_t glTypeSize; + uint32_t glFormat; + uint32_t glInternalFormat; + uint32_t glBaseInternalFormat; + uint32_t pixelWidth; + uint32_t pixelHeight; + uint32_t pixelDepth; +}; + +struct KtxBlobIndex { + uint32_t mipLevel; + uint32_t arrayIndex; + uint32_t cubeFace; +}; + +struct KtxBlobList; +struct KtxMetadata; + +/** + * Ktx1Bundle is a structured set of opaque data blobs that can be passed straight to the GPU, such + * that a single bundle corresponds to a single texture object. It is well suited for storing + * block-compressed texture data. + * + * One bundle may be comprised of several mipmap levels, cubemap faces, and array elements. The + * number of blobs is immutable, and is determined as follows. + * + * blob_count = mip_count * array_length * (cubemap ? 6 : 1) + * + * Bundles can be quickly serialized to a certain file format (see below link), but this class lives + * in the image lib rather than imageio because it has no dependencies, and does not support CPU + * decoding. + * + * https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + */ +class UTILS_PUBLIC Ktx1Bundle { +public: + + ~Ktx1Bundle(); + + /** + * Creates a hierarchy of empty texture blobs, to be filled later via setBlob(). + */ + Ktx1Bundle(uint32_t numMipLevels, uint32_t arrayLength, bool isCubemap); + + /** + * Creates a new bundle by deserializing the given data. + * + * Typically, this constructor is used to consume the contents of a KTX file. + */ + Ktx1Bundle(uint8_t const* bytes, uint32_t nbytes); + + /** + * Serializes the bundle into the given target memory. Returns false if there's not enough + * memory. + * + * Typically, this method is used to write out the contents of a KTX file. + */ + bool serialize(uint8_t* destination, uint32_t numBytes) const; + + /** + * Computes the size (in bytes) of the serialized bundle. + */ + uint32_t getSerializedLength() const; + + /** + * Gets or sets information about the texture object, such as format and type. + */ + KtxInfo const& getInfo() const { return mInfo; } + KtxInfo& info() { return mInfo; } + + /** + * Gets or sets key/value metadata. + */ + const char* getMetadata(const char* key, size_t* valueSize = nullptr) const; + void setMetadata(const char* key, const char* value); + + /** + * Parses the key="sh" metadata and returns 3 bands of data. + * + * Assumes 3 bands for a total of 9 RGB coefficients. + * Returns true if successful. + */ + bool getSphericalHarmonics(filament::math::float3* result); + + /** + * Gets the number of miplevels (this is never zero). + */ + uint32_t getNumMipLevels() const { return mNumMipLevels; } + + /** + * Gets the number of array elements (this is never zero). + */ + uint32_t getArrayLength() const { return mArrayLength; } + + /** + * Returns whether or not this is a cubemap. + */ + bool isCubemap() const { return mNumCubeFaces > 1; } + + /** + * Retrieves a weak reference to a given data blob. Returns false if the given blob index is out + * of bounds, or if the blob at the given index is empty. + */ + bool getBlob(KtxBlobIndex index, uint8_t** data, uint32_t* size) const; + + /** + * Copies the given data into the blob at the given index, replacing whatever is already there. + * Returns false if the given blob index is out of bounds. + */ + bool setBlob(KtxBlobIndex index, uint8_t const* data, uint32_t size); + + /** + * Allocates the blob at the given index to the given number of bytes. This allows subsequent + * calls to setBlob to be thread-safe. + */ + bool allocateBlob(KtxBlobIndex index, uint32_t size); + + // The following constants help clients populate the "info" struct. Most of them have corollary + // constants in the OpenGL headers. + + static constexpr uint32_t R8 = 0x8229; + static constexpr uint32_t R8_SNORM = 0x8F94; + static constexpr uint32_t R8UI = 0x8232; + static constexpr uint32_t R8I = 0x8231; + static constexpr uint32_t STENCIL_INDEX8 = 0x8D48; + static constexpr uint32_t R16F = 0x822D; + static constexpr uint32_t R16UI = 0x8234; + static constexpr uint32_t R16I = 0x8233; + static constexpr uint32_t RG8 = 0x822B; + static constexpr uint32_t RG8_SNORM = 0x8F95; + static constexpr uint32_t RG8UI = 0x8238; + static constexpr uint32_t RG8I = 0x8237; + static constexpr uint32_t RGB565 = 0x8D62; + static constexpr uint32_t RGB5_A1 = 0x8057; + static constexpr uint32_t RGBA4 = 0x8056; + static constexpr uint32_t DEPTH_COMPONENT16 = 0x81A5; + static constexpr uint32_t RGB8 = 0x8051; + static constexpr uint32_t SRGB8 = 0x8C41; + static constexpr uint32_t RGB8_SNORM = 0x8F96; + static constexpr uint32_t RGB8UI = 0x8D7D; + static constexpr uint32_t RGB8I = 0x8D8F; + static constexpr uint32_t DEPTH_COMPONENT24 = 0x81A6; + static constexpr uint32_t R32F = 0x822E; + static constexpr uint32_t R32UI = 0x8236; + static constexpr uint32_t R32I = 0x8235; + static constexpr uint32_t RG16F = 0x822F; + static constexpr uint32_t RG16UI = 0x823A; + static constexpr uint32_t RG16I = 0x8239; + static constexpr uint32_t R11F_G11F_B10F = 0x8C3A; + static constexpr uint32_t RGB9_E5 = 0x8C3D; + static constexpr uint32_t RGBA8 = 0x8058; + static constexpr uint32_t SRGB8_ALPHA8 = 0x8C43; + static constexpr uint32_t RGBA8_SNORM = 0x8F97; + static constexpr uint32_t RGB10_A2 = 0x8059; + static constexpr uint32_t RGBA8UI = 0x8D7C; + static constexpr uint32_t RGBA8I = 0x8D8E; + static constexpr uint32_t DEPTH_COMPONENT32F = 0x8CAC; + static constexpr uint32_t DEPTH24_STENCIL8 = 0x88F0; + static constexpr uint32_t DEPTH32F_STENCIL8 = 0x8CAD; + static constexpr uint32_t RGB16F = 0x881B; + static constexpr uint32_t RGB16UI = 0x8D77; + static constexpr uint32_t RGB16I = 0x8D89; + static constexpr uint32_t RG32F = 0x8230; + static constexpr uint32_t RG32UI = 0x823C; + static constexpr uint32_t RG32I = 0x823B; + static constexpr uint32_t RGBA16F = 0x881A; + static constexpr uint32_t RGBA16UI = 0x8D76; + static constexpr uint32_t RGBA16I = 0x8D88; + static constexpr uint32_t RGB32F = 0x8815; + static constexpr uint32_t RGB32UI = 0x8D71; + static constexpr uint32_t RGB32I = 0x8D83; + static constexpr uint32_t RGBA32F = 0x8814; + static constexpr uint32_t RGBA32UI = 0x8D70; + static constexpr uint32_t RGBA32I = 0x8D82; + + static constexpr uint32_t RED = 0x1903; + static constexpr uint32_t RG = 0x8227; + static constexpr uint32_t RGB = 0x1907; + static constexpr uint32_t RGBA = 0x1908; + static constexpr uint32_t BGR = 0x80E0; + static constexpr uint32_t BGRA = 0x80E1; + static constexpr uint32_t LUMINANCE = 0x1909; + static constexpr uint32_t LUMINANCE_ALPHA = 0x190A; + + static constexpr uint32_t UNSIGNED_BYTE = 0x1401; + static constexpr uint32_t UNSIGNED_SHORT = 0x1403; + static constexpr uint32_t HALF_FLOAT = 0x140B; + static constexpr uint32_t FLOAT = 0x1406; + + static constexpr uint32_t ENDIAN_DEFAULT = 0x04030201; + + static constexpr uint32_t RGB_S3TC_DXT1 = 0x83F0; + static constexpr uint32_t RGBA_S3TC_DXT1 = 0x83F1; + static constexpr uint32_t RGBA_S3TC_DXT3 = 0x83F2; + static constexpr uint32_t RGBA_S3TC_DXT5 = 0x83F3; + + static constexpr uint32_t R_RGTC_BC4_UNORM = 0x8DBB; + static constexpr uint32_t R_RGTC_BC4_SNORM = 0x8DBC; + static constexpr uint32_t RG_RGTC_BC5_UNORM = 0x8DBD; + static constexpr uint32_t RG_RGTC_BC5_SNORM = 0x8DBE; + + static constexpr uint32_t RGBA_BPTC_BC7 = 0x8E8C; + static constexpr uint32_t SRGB8_ALPHA8_BPTC_BC7 = 0x8E8D; + static constexpr uint32_t RGB_BPTC_BC6H_SNORM = 0x8E8E; + static constexpr uint32_t RGB_BPTC_BC6H_UNORM = 0x8E8F; + + static constexpr uint32_t RGBA_ASTC_4x4 = 0x93B0; + static constexpr uint32_t RGBA_ASTC_5x4 = 0x93B1; + static constexpr uint32_t RGBA_ASTC_5x5 = 0x93B2; + static constexpr uint32_t RGBA_ASTC_6x5 = 0x93B3; + static constexpr uint32_t RGBA_ASTC_6x6 = 0x93B4; + static constexpr uint32_t RGBA_ASTC_8x5 = 0x93B5; + static constexpr uint32_t RGBA_ASTC_8x6 = 0x93B6; + static constexpr uint32_t RGBA_ASTC_8x8 = 0x93B7; + static constexpr uint32_t RGBA_ASTC_10x5 = 0x93B8; + static constexpr uint32_t RGBA_ASTC_10x6 = 0x93B9; + static constexpr uint32_t RGBA_ASTC_10x8 = 0x93BA; + static constexpr uint32_t RGBA_ASTC_10x10 = 0x93BB; + static constexpr uint32_t RGBA_ASTC_12x10 = 0x93BC; + static constexpr uint32_t RGBA_ASTC_12x12 = 0x93BD; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_4x4 = 0x93D0; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_5x4 = 0x93D1; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_5x5 = 0x93D2; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_6x5 = 0x93D3; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_6x6 = 0x93D4; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x5 = 0x93D5; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x6 = 0x93D6; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x8 = 0x93D7; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x5 = 0x93D8; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x6 = 0x93D9; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x8 = 0x93DA; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x10 = 0x93DB; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_12x10 = 0x93DC; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_12x12 = 0x93DD; + + static constexpr uint32_t R11_EAC = 0x9270; + static constexpr uint32_t SIGNED_R11_EAC = 0x9271; + static constexpr uint32_t RG11_EAC = 0x9272; + static constexpr uint32_t SIGNED_RG11_EAC = 0x9273; + static constexpr uint32_t RGB8_ETC2 = 0x9274; + static constexpr uint32_t SRGB8_ETC2 = 0x9275; + static constexpr uint32_t RGB8_ALPHA1_ETC2 = 0x9276; + static constexpr uint32_t SRGB8_ALPHA1_ETC = 0x9277; + static constexpr uint32_t RGBA8_ETC2_EAC = 0x9278; + static constexpr uint32_t SRGB8_ALPHA8_ETC2_EAC = 0x9279; + +private: + image::KtxInfo mInfo = {}; + uint32_t mNumMipLevels; + uint32_t mArrayLength; + uint32_t mNumCubeFaces; + std::unique_ptr mBlobs; + std::unique_ptr mMetadata; +}; + +} // namespace image + +#endif /* IMAGE_Ktx1Bundle_H */ diff --git a/package/android/libs/filament/include/image/LinearImage.h b/package/android/libs/filament/include/image/LinearImage.h new file mode 100644 index 00000000..de46a787 --- /dev/null +++ b/package/android/libs/filament/include/image/LinearImage.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_LINEARIMAGE_H +#define IMAGE_LINEARIMAGE_H + +#include + +#include + +/** + * Types and free functions for the Filament core imaging library, primarily used for offline tools, + * but with minimal dependencies to support potential use by the renderer. + */ +namespace image { + +/** + * LinearImage is a handle to packed floating point data arranged into a row-major grid. + * + * We use this object as input/output for core algorithms that wish to be agnostic of source and + * destination formats. The number of channels is arbitrary (1 or more) but we often use 3-channel + * images to represent color data. + * + * The underlying pixel data has shared ownership semantics to allow clients to easily pass around + * the image object without incurring a deep copy. Shared access to pixels is not thread safe. + * + * By convention, we do not use channel major order (i.e. planar). However we provide a free + * function in ImageOps to combine planar data. Pixels are stored such that the row stride is simply + * width * channels * sizeof(float). + */ +class UTILS_PUBLIC LinearImage { +public: + + ~LinearImage(); + + /** + * Allocates a zeroed-out image. + */ + LinearImage(uint32_t width, uint32_t height, uint32_t channels); + + /** + * Makes a shallow copy with shared pixel data. + */ + LinearImage(const LinearImage& that); + LinearImage& operator=(const LinearImage& that); + + /** + * Creates an empty (invalid) image. + */ + LinearImage() : mDataRef(nullptr), mData(nullptr), mWidth(0), mHeight(0), mChannels(0) {} + operator bool() const { return mData != nullptr; } + + /** + * Gets a pointer to the underlying pixel data. + */ + float* getPixelRef() { return mData; } + template T* get() { return reinterpret_cast(mData); } + + /** + * Gets a pointer to immutable pixel data. + */ + float const* getPixelRef() const { return mData; } + template T const* get() const { return reinterpret_cast(mData); } + + /** + * Gets a pointer to the pixel data at the given column and row. (not bounds checked) + */ + float* getPixelRef(uint32_t column, uint32_t row) { + return mData + (column + row * mWidth) * mChannels; + } + + template + T* get(uint32_t column, uint32_t row) { + return reinterpret_cast(getPixelRef(column, row)); + } + + /** + * Gets a pointer to the immutable pixel data at the given column and row. (not bounds checked) + */ + float const* getPixelRef(uint32_t column, uint32_t row) const { + return mData + (column + row * mWidth) * mChannels; + } + + template + T const* get(uint32_t column, uint32_t row) const { + return reinterpret_cast(getPixelRef(column, row)); + } + + uint32_t getWidth() const { return mWidth; } + uint32_t getHeight() const { return mHeight; } + uint32_t getChannels() const { return mChannels; } + void reset() { *this = LinearImage(); } + bool isValid() const { return mData; } + +private: + + struct SharedReference; + SharedReference* mDataRef = nullptr; + + float* mData; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mChannels; +}; + +} // namespace image + +#endif /* IMAGE_LINEARIMAGE_H */ diff --git a/package/android/libs/filament/include/ktxreader/Ktx1Reader.h b/package/android/libs/filament/include/ktxreader/Ktx1Reader.h new file mode 100644 index 00000000..ca980c1c --- /dev/null +++ b/package/android/libs/filament/include/ktxreader/Ktx1Reader.h @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#ifndef KTXREADER_KTX1READER_H +#define KTXREADER_KTX1READER_H + +#include + +#include + +namespace filament { + class Engine; +} + +namespace ktxreader { + +using KtxInfo = image::KtxInfo; +using Ktx1Bundle = image::Ktx1Bundle; + +/** + * Allows clients to create Filament textures from Ktx1Bundle objects. + */ +namespace Ktx1Reader { + + using Texture = filament::Texture; + using Engine = filament::Engine; + + using TextureFormat = Texture::InternalFormat; + using CompressedPixelDataType = Texture::CompressedType; + using PixelDataType = Texture::Type; + using PixelDataFormat = Texture::Format; + using PixelBufferDescriptor = Texture::PixelBufferDescriptor; + + using Callback = void(*)(void* userdata); + + CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info); + PixelDataType toPixelDataType(const KtxInfo& info); + PixelDataFormat toPixelDataFormat(const KtxInfo& info); + bool isCompressed(const KtxInfo& info); + TextureFormat toTextureFormat(const KtxInfo& info); + + template + T toCompressedFilamentEnum(uint32_t format) { + switch (format) { + case Ktx1Bundle::RGB_S3TC_DXT1: return T::DXT1_RGB; + case Ktx1Bundle::RGBA_S3TC_DXT1: return T::DXT1_RGBA; + case Ktx1Bundle::RGBA_S3TC_DXT3: return T::DXT3_RGBA; + case Ktx1Bundle::RGBA_S3TC_DXT5: return T::DXT5_RGBA; + case Ktx1Bundle::R_RGTC_BC4_UNORM: return T::RED_RGTC1; + case Ktx1Bundle::R_RGTC_BC4_SNORM: return T::SIGNED_RED_RGTC1; + case Ktx1Bundle::RG_RGTC_BC5_UNORM: return T::RED_GREEN_RGTC2; + case Ktx1Bundle::RG_RGTC_BC5_SNORM: return T::SIGNED_RED_GREEN_RGTC2; + case Ktx1Bundle::RGBA_BPTC_BC7: return T::RGBA_BPTC_UNORM; + case Ktx1Bundle::SRGB8_ALPHA8_BPTC_BC7: return T::SRGB_ALPHA_BPTC_UNORM; + case Ktx1Bundle::RGB_BPTC_BC6H_SNORM: return T::RGB_BPTC_SIGNED_FLOAT; + case Ktx1Bundle::RGB_BPTC_BC6H_UNORM: return T::RGB_BPTC_UNSIGNED_FLOAT; + case Ktx1Bundle::RGBA_ASTC_4x4: return T::RGBA_ASTC_4x4; + case Ktx1Bundle::RGBA_ASTC_5x4: return T::RGBA_ASTC_5x4; + case Ktx1Bundle::RGBA_ASTC_5x5: return T::RGBA_ASTC_5x5; + case Ktx1Bundle::RGBA_ASTC_6x5: return T::RGBA_ASTC_6x5; + case Ktx1Bundle::RGBA_ASTC_6x6: return T::RGBA_ASTC_6x6; + case Ktx1Bundle::RGBA_ASTC_8x5: return T::RGBA_ASTC_8x5; + case Ktx1Bundle::RGBA_ASTC_8x6: return T::RGBA_ASTC_8x6; + case Ktx1Bundle::RGBA_ASTC_8x8: return T::RGBA_ASTC_8x8; + case Ktx1Bundle::RGBA_ASTC_10x5: return T::RGBA_ASTC_10x5; + case Ktx1Bundle::RGBA_ASTC_10x6: return T::RGBA_ASTC_10x6; + case Ktx1Bundle::RGBA_ASTC_10x8: return T::RGBA_ASTC_10x8; + case Ktx1Bundle::RGBA_ASTC_10x10: return T::RGBA_ASTC_10x10; + case Ktx1Bundle::RGBA_ASTC_12x10: return T::RGBA_ASTC_12x10; + case Ktx1Bundle::RGBA_ASTC_12x12: return T::RGBA_ASTC_12x12; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_4x4: return T::SRGB8_ALPHA8_ASTC_4x4; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x4: return T::SRGB8_ALPHA8_ASTC_5x4; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x5: return T::SRGB8_ALPHA8_ASTC_5x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x5: return T::SRGB8_ALPHA8_ASTC_6x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x6: return T::SRGB8_ALPHA8_ASTC_6x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x5: return T::SRGB8_ALPHA8_ASTC_8x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x6: return T::SRGB8_ALPHA8_ASTC_8x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x8: return T::SRGB8_ALPHA8_ASTC_8x8; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x5: return T::SRGB8_ALPHA8_ASTC_10x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x6: return T::SRGB8_ALPHA8_ASTC_10x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x8: return T::SRGB8_ALPHA8_ASTC_10x8; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x10: return T::SRGB8_ALPHA8_ASTC_10x10; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x10: return T::SRGB8_ALPHA8_ASTC_12x10; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x12: return T::SRGB8_ALPHA8_ASTC_12x12; + case Ktx1Bundle::R11_EAC: return T::EAC_R11; + case Ktx1Bundle::SIGNED_R11_EAC: return T::EAC_R11_SIGNED; + case Ktx1Bundle::RG11_EAC: return T::EAC_RG11; + case Ktx1Bundle::SIGNED_RG11_EAC: return T::EAC_RG11_SIGNED; + case Ktx1Bundle::RGB8_ETC2: return T::ETC2_RGB8; + case Ktx1Bundle::SRGB8_ETC2: return T::ETC2_SRGB8; + case Ktx1Bundle::RGB8_ALPHA1_ETC2: return T::ETC2_RGB8_A1; + case Ktx1Bundle::SRGB8_ALPHA1_ETC: return T::ETC2_SRGB8_A1; + case Ktx1Bundle::RGBA8_ETC2_EAC: return T::ETC2_EAC_RGBA8; + case Ktx1Bundle::SRGB8_ALPHA8_ETC2_EAC: return T::ETC2_EAC_SRGBA8; + } + return (T) 0xffff; + } + + /** + * Creates a Texture object from a KTX file and populates all of its faces and miplevels. + * + * @param engine Used to create the Filament Texture + * @param ktx In-memory representation of a KTX file + * @param srgb Requests an sRGB format from the KTX file + * @param callback Gets called after all texture data has been uploaded to the GPU + * @param userdata Passed into the callback + */ + Texture* createTexture(Engine* engine, const Ktx1Bundle& ktx, bool srgb, + Callback callback, void* userdata); + + /** + * Creates a Texture object from a KTX bundle, populates all of its faces and miplevels, + * and automatically destroys the bundle after all the texture data has been uploaded. + * + * @param engine Used to create the Filament Texture + * @param ktx In-memory representation of a KTX file + * @param srgb Requests an sRGB format from the KTX file + */ + Texture* createTexture(Engine* engine, Ktx1Bundle* ktx, bool srgb); + + CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info); + + PixelDataType toPixelDataType(const KtxInfo& info); + + PixelDataFormat toPixelDataFormat(const KtxInfo& info); + + bool isCompressed(const KtxInfo& info); + + bool isSrgbTextureFormat(TextureFormat format); + + TextureFormat toTextureFormat(const KtxInfo& info); + +} // namespace Ktx1Reader +} // namespace ktxreader + +#endif diff --git a/package/android/libs/filament/include/ktxreader/Ktx2Reader.h b/package/android/libs/filament/include/ktxreader/Ktx2Reader.h new file mode 100644 index 00000000..0994a5e2 --- /dev/null +++ b/package/android/libs/filament/include/ktxreader/Ktx2Reader.h @@ -0,0 +1,203 @@ +/* + * 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. + */ + +#ifndef KTXREADER_KTX2READER_H +#define KTXREADER_KTX2READER_H + +#include +#include + +#include + +#include + +namespace filament { + class Engine; +} + +namespace basist { + class ktx2_transcoder; +} + +namespace ktxreader { + +class Ktx2Reader { + public: + using Engine = filament::Engine; + using Texture = filament::Texture; + enum class TransferFunction { LINEAR, sRGB }; + + enum class Result { + SUCCESS, + COMPRESSED_TRANSCODE_FAILURE, + UNCOMPRESSED_TRANSCODE_FAILURE, + FORMAT_UNSUPPORTED, + FORMAT_ALREADY_REQUESTED, + }; + + Ktx2Reader(Engine& engine, bool quiet = false); + ~Ktx2Reader(); + + /** + * Requests that the reader constructs Filament textures with given internal format. + * + * This MUST be called at least once before calling load(). + * + * As a reminder, a basis-encoded KTX2 can be quickly transcoded to any number of formats, + * so you need to tell it what formats your hw supports. That's why this method exists. + * + * Call requestFormat as many times as needed; formats that are submitted early are + * considered higher priority. + * + * If BasisU knows a priori that the given format is not available (e.g. if the build has + * disabled it), the format is not added and FORMAT_UNSUPPORTED is returned. + * + * Returns FORMAT_ALREADY_REQUESTED if the given format has already been requested. + * + * Hint: BasisU supports the following uncompressed formats: RGBA8, RGB565, RGBA4. + */ + Result requestFormat(Texture::InternalFormat format) noexcept; + + /** + * Removes the given format from the list, or does nothing if it hasn't been requested. + */ + void unrequestFormat(Texture::InternalFormat format) noexcept; + + /** + * Attempts to create and load a Filament texture from the given KTX2 blob. + * + * If none of the requested formats can be extracted from the data, this returns null. + * + * This method iterates through the requested format list, checking each one against the + * platform's capabilities and its availability from the transcoder. When a suitable format + * is determined, it then performs lossless decompression (zstd) before transcoding the data + * into the final format. + * + * The transfer function specified here is used in two ways: + * 1) It is checked against the transfer function that was specified as metadata + * in the KTX2 blob. If they do not match, this method fails. + * 2) It is used as a filter when determining the final internal format. + */ + Texture* load(const void* data, size_t size, TransferFunction transfer); + + /** + * Asynchronous Interface + * ====================== + * + * Alternative API suitable for asynchronous transcoding of mipmap levels. + * If unsure that you need to use this, then don't, just call load() instead. + * Usage pseudocode: + * + * auto async = reader->asyncCreate(data, size, TransferFunction::LINEAR); + * mTexture = async->getTexture(); + * auto backgroundThread = spawnThread({ async->doTranscoding(); }) + * backgroundThread.wait(); + * async->uploadImages(); + * reader->asyncDestroy(async); + * + * In the documentation comments, "foreground thread" refers to the thread that the + * Filament Engine was created on. + */ + class Async { + public: + /** + * Retrieves the Texture object. + * + * The texture is available immediately, but does not have its miplevels ready until + * after doTranscoding() and the subsequent uploadImages() have been completed. The + * caller has ownership over this texture and is responsible for freeing it after all + * miplevels have been uploaded. + */ + Texture* getTexture() const noexcept; + + /** + * Loads all mipmaps from the KTX2 file and transcodes them to the resolved format. + * + * This does not return until all mipmaps have been transcoded. This is typically + * called from a background thread. + */ + Result doTranscoding(); + + /** + * Uploads pending mipmaps to the texture. + * + * This can safely be called while doTranscoding() is still working in another thread. + * Since this calls Texture::setImage(), it should be called from the foreground thread; + * see "Thread safety" in the documentation for filament::Engine. + */ + void uploadImages(); + + protected: + Async() noexcept = default; + virtual ~Async(); + + public: + Async(Async const&) = delete; + Async(Async&&) = delete; + Async& operator=(Async const&) = delete; + Async& operator=(Async&&) = delete; + + friend class Ktx2Reader; + }; + + /** + * Creates a texture without starting the transcode process. + * + * This method is an alternative to load() that allows users to populate mipmap levels + * asynchronously. The texture object however is still created synchronously. + * + * - For a usage example, see the documentation for the Async object. + * - Creates a copy of the given buffer, allowing clients to free it immediately. + * - Returns null if none of the requested formats can be extracted from the data. + * + * This method iterates through the requested format list, checking each one against the + * platform's capabilities and its availability from the transcoder. When a suitable format + * is determined, it then performs lossless decompression (zstd) before transcoding the data + * into the final format. + * + * The transfer function specified here is used in two ways: + * 1) It is checked against the transfer function that was specified as metadata + * in the KTX2 blob. If they do not match, this method fails. + * 2) It is used as a filter when determining the final internal format. + */ + Async* asyncCreate(const void* data, size_t size, TransferFunction transfer); + + /** + * Frees the given async object and sets it to null. + * + * This frees the original source data (i.e. the raw content of the KTX2 file) but does not + * free the associated Texture object. This can be done after transcoding has finished. + */ + void asyncDestroy(Async** async); + + private: + Ktx2Reader(const Ktx2Reader&) = delete; + Ktx2Reader& operator=(const Ktx2Reader&) = delete; + Ktx2Reader(Ktx2Reader&& that) noexcept = delete; + Ktx2Reader& operator=(Ktx2Reader&& that) noexcept = delete; + + Texture* createTexture(basist::ktx2_transcoder* transcoder, const void* data, + size_t size, TransferFunction transfer); + + Engine& mEngine; + basist::ktx2_transcoder* const mTranscoder; + utils::FixedCapacityVector mRequestedFormats; + bool mQuiet; +}; + +} // namespace ktxreader + +#endif diff --git a/package/android/libs/filament/include/math/TMatHelpers.h b/package/android/libs/filament/include/math/TMatHelpers.h new file mode 100644 index 00000000..ec66650c --- /dev/null +++ b/package/android/libs/filament/include/math/TMatHelpers.h @@ -0,0 +1,807 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TMATHELPERS_H +#define TNT_MATH_TMATHELPERS_H + +#include +#include +#include + +#include // for std::swap and std::min +#include // for std:: namespace + +#include +#include +#include + +namespace filament { +namespace math { +namespace details { +// ------------------------------------------------------------------------------------- + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/mat*.h + */ + + +/* + * Matrix utilities + */ + +namespace matrix { + +/* + * Matrix inversion + */ +template +constexpr MATRIX MATH_PURE gaussJordanInverse(MATRIX src) { + typedef typename MATRIX::value_type T; + constexpr unsigned int N = MATRIX::NUM_ROWS; + MATRIX inverted; + + for (size_t i = 0; i < N; ++i) { + // look for largest element in i'th column + size_t swap = i; + T t = src[i][i] < 0 ? -src[i][i] : src[i][i]; + for (size_t j = i + 1; j < N; ++j) { + const T t2 = src[j][i] < 0 ? -src[j][i] : src[j][i]; + if (t2 > t) { + swap = j; + t = t2; + } + } + + if (swap != i) { + // swap columns. + std::swap(src[i], src[swap]); + std::swap(inverted[i], inverted[swap]); + } + + const T denom(src[i][i]); + for (size_t k = 0; k < N; ++k) { + src[i][k] /= denom; + inverted[i][k] /= denom; + } + + // Factor out the lower triangle + for (size_t j = 0; j < N; ++j) { + if (j != i) { + const T t = src[j][i]; + for (size_t k = 0; k < N; ++k) { + src[j][k] -= src[i][k] * t; + inverted[j][k] -= inverted[i][k] * t; + } + } + } + } + + return inverted; +} + +//------------------------------------------------------------------------------ +// 2x2 matrix inverse is easy. +template +constexpr MATRIX MATH_PURE fastInverse2(const MATRIX& x) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b | + // | c d | + // + // The analytic inverse is + // | d -b | + // | -c a | / (a d - b c) + // + // Importantly, our matrices are column-major! + + MATRIX inverted{}; + + const T a = x[0][0]; + const T c = x[0][1]; + const T b = x[1][0]; + const T d = x[1][1]; + + const T det((a * d) - (b * c)); + inverted[0][0] = d / det; + inverted[0][1] = -c / det; + inverted[1][0] = -b / det; + inverted[1][1] = a / det; + return inverted; +} + +//------------------------------------------------------------------------------ +// From the Wikipedia article on matrix inversion's section on fast 3x3 +// matrix inversion: +// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices +template +constexpr MATRIX MATH_PURE fastInverse3(const MATRIX& x) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b c | + // | d e f | + // | g h i | + // + // The analytic inverse is + // | A B C |^T + // | D E F | + // | G H I | / determinant + // + // Which is + // | A D G | + // | B E H | + // | C F I | / determinant + // + // Where: + // A = (ei - fh), B = (fg - di), C = (dh - eg) + // D = (ch - bi), E = (ai - cg), F = (bg - ah) + // G = (bf - ce), H = (cd - af), I = (ae - bd) + // + // and the determinant is a*A + b*B + c*C (The rule of Sarrus) + // + // Importantly, our matrices are column-major! + + MATRIX inverted{}; + + const T a = x[0][0]; + const T b = x[1][0]; + const T c = x[2][0]; + const T d = x[0][1]; + const T e = x[1][1]; + const T f = x[2][1]; + const T g = x[0][2]; + const T h = x[1][2]; + const T i = x[2][2]; + + // Do the full analytic inverse + const T A = e * i - f * h; + const T B = f * g - d * i; + const T C = d * h - e * g; + inverted[0][0] = A; // A + inverted[0][1] = B; // B + inverted[0][2] = C; // C + inverted[1][0] = c * h - b * i; // D + inverted[1][1] = a * i - c * g; // E + inverted[1][2] = b * g - a * h; // F + inverted[2][0] = b * f - c * e; // G + inverted[2][1] = c * d - a * f; // H + inverted[2][2] = a * e - b * d; // I + + const T det(a * A + b * B + c * C); + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + inverted[col][row] /= det; + } + } + + return inverted; +} + + +//------------------------------------------------------------------------------ +// Determinant and cofactor + +// this is just a dummy matrix helper +template +class Matrix { + T m[ORDER][ORDER]; +public: + constexpr auto operator[](size_t i) const noexcept { return m[i]; } + + constexpr auto& operator[](size_t i) noexcept { return m[i]; } + + static constexpr Matrix submatrix(Matrix in, size_t row, size_t col) noexcept { + size_t colCount = 0, rowCount = 0; + Matrix dest{}; + for (size_t i = 0; i < ORDER; i++) { + if (i != row) { + colCount = 0; + for (size_t j = 0; j < ORDER; j++) { + if (j != col) { + dest[rowCount][colCount] = in[i][j]; + colCount++; + } + } + rowCount++; + } + } + return dest; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + T det = {}; + for (size_t i = 0; i < O; i++) { + T m = Determinant::determinant(Matrix::submatrix(in, 0, i)); + T factor = (i % 2 == 1) ? T(-1) : T(1); + det += factor * in[0][i] * m; + } + return det; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + return + in[0][0] * in[1][1] * in[2][2] + + in[1][0] * in[2][1] * in[0][2] + + in[2][0] * in[0][1] * in[1][2] - + in[2][0] * in[1][1] * in[0][2] - + in[1][0] * in[0][1] * in[2][2] - + in[0][0] * in[2][1] * in[1][2]; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + return in[0][0] * in[1][1] - in[0][1] * in[1][0]; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { return in[0][0]; } +}; + +template +constexpr MATRIX MATH_PURE cofactor(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + MATRIX out; + constexpr size_t order = MATRIX::NUM_COLS; + + Matrix in{}; + for (size_t i = 0; i < order; i++) { + for (size_t j = 0; j < order; j++) { + in[i][j] = m[i][j]; + } + } + + for (size_t i = 0; i < order; i++) { + for (size_t j = 0; j < order; j++) { + T factor = ((i + j) % 2 == 1) ? T(-1) : T(1); + out[i][j] = Determinant::determinant( + Matrix::submatrix(in, i, j)) * factor; + } + } + return out; +} + +template +constexpr MATRIX MATH_PURE fastCofactor2(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b | + // | c d | + // + // The cofactor are + // | d -c | + // | -b a | + // + // Importantly, our matrices are column-major! + + MATRIX cof{}; + + const T a = m[0][0]; + const T c = m[0][1]; + const T b = m[1][0]; + const T d = m[1][1]; + + cof[0][0] = d; + cof[0][1] = -b; + cof[1][0] = -c; + cof[1][1] = a; + return cof; +} + +template +constexpr MATRIX MATH_PURE fastCofactor3(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b c | + // | d e f | + // | g h i | + // + // The cofactor are + // | A B C | + // | D E F | + // | G H I | + + // Where: + // A = (ei - fh), B = (fg - di), C = (dh - eg) + // D = (ch - bi), E = (ai - cg), F = (bg - ah) + // G = (bf - ce), H = (cd - af), I = (ae - bd) + + // Importantly, our matrices are column-major! + + MATRIX cof{}; + + const T a = m[0][0]; + const T b = m[1][0]; + const T c = m[2][0]; + const T d = m[0][1]; + const T e = m[1][1]; + const T f = m[2][1]; + const T g = m[0][2]; + const T h = m[1][2]; + const T i = m[2][2]; + + cof[0][0] = e * i - f * h; // A + cof[0][1] = c * h - b * i; // D + cof[0][2] = b * f - c * e; // G + cof[1][0] = f * g - d * i; // B + cof[1][1] = a * i - c * g; // E + cof[1][2] = c * d - a * f; // H + cof[2][0] = d * h - e * g; // C + cof[2][1] = b * g - a * h; // F + cof[2][2] = a * e - b * d; // I + + return cof; +} + + +/** + * Cofactor function which switches on the matrix size. + */ +template> +inline constexpr MATRIX MATH_PURE cof(const MATRIX& matrix) { + return (MATRIX::NUM_ROWS == 2) ? fastCofactor2(matrix) : + ((MATRIX::NUM_ROWS == 3) ? fastCofactor3(matrix) : + cofactor(matrix)); +} + +/** + * Determinant of a matrix + */ +template> +inline constexpr typename MATRIX::value_type MATH_PURE det(const MATRIX& matrix) { + typedef typename MATRIX::value_type T; + constexpr unsigned int N = MATRIX::NUM_ROWS; + Matrix in{}; + for (size_t i = 0; i < N; i++) { + for (size_t j = 0; j < N; j++) { + in[i][j] = matrix[i][j]; + } + } + return Determinant::determinant(in); +} + +/** + * Inversion function which switches on the matrix size. + * @warning This function assumes the matrix is invertible. The result is + * undefined if it is not. It is the responsibility of the caller to + * make sure the matrix is not singular. + */ +template> +inline constexpr MATRIX MATH_PURE inverse(const MATRIX& matrix) { + return (MATRIX::NUM_ROWS == 2) ? fastInverse2(matrix) : + ((MATRIX::NUM_ROWS == 3) ? fastInverse3(matrix) : + gaussJordanInverse(matrix)); +} + +template> +constexpr MATRIX_R MATH_PURE multiply(MATRIX_A lhs, MATRIX_B rhs) { + // pre-requisite: + // lhs : D columns, R rows + // rhs : C columns, D rows + // res : C columns, R rows + MATRIX_R res{}; + for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) { + res[col] = lhs * rhs[col]; + } + return res; +} + +template> +inline constexpr MATRIX MATH_PURE transpose(MATRIX m) { + // for now we only handle square matrix transpose + MATRIX result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) { + result[col][row] = m[row][col]; + } + } + return result; +} + +template> +inline constexpr typename MATRIX::value_type MATH_PURE trace(MATRIX m) { + typename MATRIX::value_type result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + result += m[col][col]; + } + return result; +} + +template> +inline constexpr typename MATRIX::col_type MATH_PURE diag(MATRIX m) { + typename MATRIX::col_type result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + result[col] = m[col][col]; + } + return result; +} + +//------------------------------------------------------------------------------ +// This is taken from the Imath MatrixAlgo code, and is identical to Eigen. +template +TQuaternion extractQuat(const MATRIX& mat) { + typedef typename MATRIX::value_type T; + + TQuaternion quat(TQuaternion::NO_INIT); + + // Compute the trace to see if it is positive or not. + const T trace = mat[0][0] + mat[1][1] + mat[2][2]; + + // check the sign of the trace + if (MATH_LIKELY(trace > 0)) { + // trace is positive + T s = std::sqrt(trace + 1); + quat.w = T(0.5) * s; + s = T(0.5) / s; + quat.x = (mat[1][2] - mat[2][1]) * s; + quat.y = (mat[2][0] - mat[0][2]) * s; + quat.z = (mat[0][1] - mat[1][0]) * s; + } else { + // trace is negative + + // Find the index of the greatest diagonal + size_t i = 0; + if (mat[1][1] > mat[0][0]) { i = 1; } + if (mat[2][2] > mat[i][i]) { i = 2; } + + // Get the next indices: (n+1)%3 + static constexpr size_t next_ijk[3] = { 1, 2, 0 }; + size_t j = next_ijk[i]; + size_t k = next_ijk[j]; + T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1); + quat[i] = T(0.5) * s; + if (s != 0) { + s = T(0.5) / s; + } + quat.w = (mat[j][k] - mat[k][j]) * s; + quat[j] = (mat[i][j] + mat[j][i]) * s; + quat[k] = (mat[i][k] + mat[k][i]) * s; + } + return quat; +} + +} // namespace matrix + +// ------------------------------------------------------------------------------------- + +/* + * TMatProductOperators implements basic arithmetic and basic compound assignments + * operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TMatProductOperators BASE will automatically + * get all the functionality here. + */ + +template class BASE, typename T, + template class VEC> +class TMatProductOperators { +public: + // matrix *= matrix + template + constexpr BASE& operator*=(const BASE& rhs) { + BASE& lhs(static_cast< BASE& >(*this)); + lhs = matrix::multiply>(lhs, rhs); + return lhs; + } + + // matrix *= scalar + template> + constexpr BASE& operator*=(U v) { + BASE& lhs(static_cast< BASE& >(*this)); + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + lhs[col] *= v; + } + return lhs; + } + + // matrix /= scalar + template> + constexpr BASE& operator/=(U v) { + BASE& lhs(static_cast< BASE& >(*this)); + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + lhs[col] /= v; + } + return lhs; + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + // matrix * matrix + template + friend inline constexpr BASE> MATH_PURE + operator*(BASE lhs, BASE rhs) { + return matrix::multiply>>(lhs, rhs); + } + + // matrix * vector + template + friend inline constexpr typename BASE>::col_type MATH_PURE + operator*(const BASE& lhs, const VEC& rhs) { + typename BASE>::col_type result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result += lhs[col] * rhs[col]; + } + return result; + } + + // row-vector * matrix + template + friend inline constexpr typename BASE>::row_type MATH_PURE + operator*(const VEC& lhs, const BASE& rhs) { + typename BASE>::row_type result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = dot(lhs, rhs[col]); + } + return result; + } + + // matrix * scalar + template> + friend inline constexpr BASE> MATH_PURE + operator*(const BASE& lhs, U rhs) { + BASE> result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = lhs[col] * rhs; + } + return result; + } + + // scalar * matrix + template> + friend inline constexpr BASE> MATH_PURE + operator*(U rhs, const BASE& lhs) { + return lhs * rhs; + } + + // matrix / scalar + template> + friend inline constexpr BASE> MATH_PURE + operator/(const BASE& lhs, U rhs) { + BASE> result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = lhs[col] / rhs; + } + return result; + } +}; + +/* + * TMatSquareFunctions implements functions on a matrix of type BASE. + * + * BASE only needs to implement: + * - operator[] + * - col_type + * - row_type + * - COL_SIZE + * - ROW_SIZE + * + * By simply inheriting from TMatSquareFunctions BASE will automatically + * get all the functionality here. + */ + +template class BASE, typename T> +class TMatSquareFunctions { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + friend inline constexpr BASE MATH_PURE inverse(const BASE& matrix) { + return matrix::inverse(matrix); + } + + friend inline constexpr BASE MATH_PURE cof(const BASE& matrix) { + return matrix::cof(matrix); + } + + friend inline constexpr BASE MATH_PURE transpose(BASE m) { + return matrix::transpose(m); + } + + friend inline constexpr T MATH_PURE trace(BASE m) { + return matrix::trace(m); + } + + friend inline constexpr T MATH_PURE det(const BASE& m) { + return matrix::det(m); + } + + // unclear why we have to use 'auto' here. 'typename BASE::col_type' produces + // error: no type named 'col_type' in 'filament::math::details::TMat44' + friend inline constexpr auto MATH_PURE diag(const BASE& m) { + return matrix::diag(m); + } +}; + +template class BASE, typename T> +class TMatHelpers { +public: + constexpr inline size_t getColumnSize() const { return BASE::COL_SIZE; } + constexpr inline size_t getRowSize() const { return BASE::ROW_SIZE; } + constexpr inline size_t getColumnCount() const { return BASE::NUM_COLS; } + constexpr inline size_t getRowCount() const { return BASE::NUM_ROWS; } + constexpr inline size_t size() const { return BASE::ROW_SIZE; } // for TVec*<> + + // array access + constexpr T const* asArray() const { + return &static_cast const &>(*this)[0][0]; + } + + // element access + inline constexpr T const& operator()(size_t row, size_t col) const { + return static_cast const &>(*this)[col][row]; + } + + inline T& operator()(size_t row, size_t col) { + return static_cast&>(*this)[col][row]; + } + +private: + constexpr friend inline BASE MATH_PURE abs(BASE m) { + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + m[col] = abs(m[col]); + } + return m; + } +}; + +// functions for 3x3 and 4x4 matrices +template class BASE, typename T> +class TMatTransform { +public: + inline constexpr TMatTransform() { + static_assert(BASE::NUM_ROWS == 3 || BASE::NUM_ROWS == 4, "3x3 or 4x4 matrices only"); + } + + template> + static BASE rotation(A radian, VEC about) { + BASE r; + T c = std::cos(radian); + T s = std::sin(radian); + if (about[0] == 1 && about[1] == 0 && about[2] == 0) { + r[1][1] = c; r[2][2] = c; + r[1][2] = s; r[2][1] = -s; + } else if (about[0] == 0 && about[1] == 1 && about[2] == 0) { + r[0][0] = c; r[2][2] = c; + r[2][0] = s; r[0][2] = -s; + } else if (about[0] == 0 && about[1] == 0 && about[2] == 1) { + r[0][0] = c; r[1][1] = c; + r[0][1] = s; r[1][0] = -s; + } else { + VEC nabout = normalize(about); + typename VEC::value_type x = nabout[0]; + typename VEC::value_type y = nabout[1]; + typename VEC::value_type z = nabout[2]; + T nc = 1 - c; + T xy = x * y; + T yz = y * z; + T zx = z * x; + T xs = x * s; + T ys = y * s; + T zs = z * s; + r[0][0] = x*x*nc + c; r[1][0] = xy*nc - zs; r[2][0] = zx*nc + ys; + r[0][1] = xy*nc + zs; r[1][1] = y*y*nc + c; r[2][1] = yz*nc - xs; + r[0][2] = zx*nc - ys; r[1][2] = yz*nc + xs; r[2][2] = z*z*nc + c; + + // Clamp results to -1, 1. + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1)); + } + } + } + return r; + } + + /** + * Create a matrix from euler angles using YPR around YXZ respectively + * @param yaw about Y axis + * @param pitch about X axis + * @param roll about Z axis + */ + template> + static BASE eulerYXZ(Y yaw, P pitch, R roll) { + return eulerZYX(roll, pitch, yaw); + } + + /** + * Create a matrix from euler angles using YPR around ZYX respectively + * @param roll about X axis + * @param pitch about Y axis + * @param yaw about Z axis + * + * The euler angles are applied in ZYX order. i.e: a vector is first rotated + * about X (roll) then Y (pitch) and then Z (yaw). + */ + template> + static BASE eulerZYX(Y yaw, P pitch, R roll) { + BASE r; + T cy = std::cos(yaw); + T sy = std::sin(yaw); + T cp = std::cos(pitch); + T sp = std::sin(pitch); + T cr = std::cos(roll); + T sr = std::sin(roll); + T cc = cr * cy; + T cs = cr * sy; + T sc = sr * cy; + T ss = sr * sy; + r[0][0] = cp * cy; + r[0][1] = cp * sy; + r[0][2] = -sp; + r[1][0] = sp * sc - cs; + r[1][1] = sp * ss + cc; + r[1][2] = cp * sr; + r[2][0] = sp * cc + ss; + r[2][1] = sp * cs - sc; + r[2][2] = cp * cr; + + // Clamp results to -1, 1. + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1)); + } + } + return r; + } + + TQuaternion toQuaternion() const { + return matrix::extractQuat(static_cast&>(*this)); + } +}; + +// ------------------------------------------------------------------------------------- +} // namespace details +} // namespace math +} // namespace filament + +#endif // TNT_MATH_TMATHELPERS_H diff --git a/package/android/libs/filament/include/math/TQuatHelpers.h b/package/android/libs/filament/include/math/TQuatHelpers.h new file mode 100644 index 00000000..0439b971 --- /dev/null +++ b/package/android/libs/filament/include/math/TQuatHelpers.h @@ -0,0 +1,294 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TQUATHELPERS_H +#define TNT_MATH_TQUATHELPERS_H + +#include +#include +#include + +#include +#include +#include + +namespace filament::math::details { + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/quat.h + */ + + +/* + * TQuatProductOperators implements basic arithmetic and basic compound assignment + * operators on a quaternion of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TQuatProductOperators BASE will automatically + * get all the functionality here. + */ + +template class QUATERNION, typename T> +class TQuatProductOperators { +public: + /* compound assignment from another quaternion of the same size but different + * element type. + */ + template + constexpr QUATERNION& operator*=(const QUATERNION& r) { + QUATERNION& q = static_cast&>(*this); + q = q * r; + return q; + } + + /* compound assignment products by a scalar + */ + template>> + constexpr QUATERNION& operator*=(U v) { + QUATERNION& lhs = static_cast&>(*this); + for (size_t i = 0; i < QUATERNION::size(); i++) { + lhs[i] *= v; + } + return lhs; + } + + template>> + constexpr QUATERNION& operator/=(U v) { + QUATERNION& lhs = static_cast&>(*this); + for (size_t i = 0; i < QUATERNION::size(); i++) { + lhs[i] /= v; + } + return lhs; + } + + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + /* The operators below handle operation between quaternions of the same size + * but of a different element type. + */ + template + friend inline constexpr + QUATERNION> MATH_PURE operator*( + const QUATERNION& q, const QUATERNION& r) { + // could be written as: + // return QUATERNION( + // q.w*r.w - dot(q.xyz, r.xyz), + // q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz)); + return { + q.w * r.w - q.x * r.x - q.y * r.y - q.z * r.z, + q.w * r.x + q.x * r.w + q.y * r.z - q.z * r.y, + q.w * r.y - q.x * r.z + q.y * r.w + q.z * r.x, + q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w + }; + } + + template + friend inline constexpr + TVec3> MATH_PURE operator*(const QUATERNION& q, const TVec3& v) { + // note: if q is known to be a unit quaternion, then this simplifies to: + // TVec3 t = 2 * cross(q.xyz, v) + // return v + (q.w * t) + cross(q.xyz, t) + return imaginary(q * QUATERNION(v, 0) * inverse(q)); + } + + + /* For quaternions, we use explicit "by a scalar" products because it's much faster + * than going (implicitly) through the quaternion multiplication. + * For reference: we could use the code below instead, but it would be a lot slower. + * friend inline + * constexpr BASE MATH_PURE operator *(const BASE& q, const BASE& r) { + * return BASE( + * q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z, + * q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y, + * q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x, + * q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w); + * + */ + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator*(QUATERNION q, U scalar) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q *= scalar); + } + + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator*(U scalar, QUATERNION q) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q *= scalar); + } + + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator/(QUATERNION q, U scalar) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q /= scalar); + } +}; + + +/* + * TQuatFunctions implements functions on a quaternion of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TQuatFunctions BASE will automatically + * get all the functionality here. + */ +template class QUATERNION, typename T> +class TQuatFunctions { +public: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + arithmetic_result_t MATH_PURE dot( + const QUATERNION& p, const QUATERNION& q) { + return p.x * q.x + + p.y * q.y + + p.z * q.z + + p.w * q.w; + } + + friend inline + T MATH_PURE norm(const QUATERNION& q) { + return std::sqrt(dot(q, q)); + } + + friend inline + T MATH_PURE length(const QUATERNION& q) { + return norm(q); + } + + friend inline + constexpr T MATH_PURE length2(const QUATERNION& q) { + return dot(q, q); + } + + friend inline + QUATERNION MATH_PURE normalize(const QUATERNION& q) { + return length(q) ? q / length(q) : QUATERNION(static_cast(1)); + } + + friend inline + constexpr QUATERNION MATH_PURE conj(const QUATERNION& q) { + return QUATERNION(q.w, -q.x, -q.y, -q.z); + } + + friend inline + constexpr QUATERNION MATH_PURE inverse(const QUATERNION& q) { + return conj(q) * (T(1) / dot(q, q)); + } + + friend inline + constexpr T MATH_PURE real(const QUATERNION& q) { + return q.w; + } + + friend inline + constexpr TVec3 MATH_PURE imaginary(const QUATERNION& q) { + return q.xyz; + } + + friend inline + constexpr QUATERNION MATH_PURE unreal(const QUATERNION& q) { + return QUATERNION(q.xyz, 0); + } + + template + friend inline constexpr + QUATERNION> MATH_PURE cross( + const QUATERNION& p, const QUATERNION& q) { + return unreal(p * q); + } + + friend inline + QUATERNION MATH_PURE exp(const QUATERNION& q) { + const T nq(norm(q.xyz)); + return std::exp(q.w) * QUATERNION((sin(nq) / nq) * q.xyz, cos(nq)); + } + + friend inline + QUATERNION MATH_PURE log(const QUATERNION& q) { + const T nq(norm(q)); + return QUATERNION((std::acos(q.w / nq) / norm(q.xyz)) * q.xyz, std::log(nq)); + } + + friend inline + QUATERNION MATH_PURE pow(const QUATERNION& q, T a) { + // could also be computed as: exp(a*log(q)); + const T nq(norm(q)); + const T theta(a * std::acos(q.w / nq)); + return std::pow(nq, a) * QUATERNION(normalize(q.xyz) * std::sin(theta), std::cos(theta)); + } + + friend inline + QUATERNION MATH_PURE slerp(const QUATERNION& p, const QUATERNION& q, T t) { + // could also be computed as: pow(q * inverse(p), t) * p; + const T d = dot(p, q); + const T absd = std::abs(d); + static constexpr T value_eps = T(10) * std::numeric_limits::epsilon(); + // Prevent blowing up when slerping between two quaternions that are very near each other. + if ((T(1) - absd) < value_eps) { + return normalize(lerp(d < 0 ? -p : p, q, t)); + } + const T npq = std::sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q|| + const T a = std::acos(filament::math::clamp(absd / npq, T(-1), T(1))); + const T a0 = a * (1 - t); + const T a1 = a * t; + const T sina = sin(a); + if (sina < value_eps) { + return normalize(lerp(p, q, t)); + } + const T isina = 1 / sina; + const T s0 = std::sin(a0) * isina; + const T s1 = std::sin(a1) * isina; + // ensure we're taking the "short" side + return normalize(s0 * p + ((d < 0) ? (-s1) : (s1)) * q); + } + + friend inline + constexpr QUATERNION MATH_PURE lerp(const QUATERNION& p, const QUATERNION& q, T t) { + return ((1 - t) * p) + (t * q); + } + + friend inline + constexpr QUATERNION MATH_PURE nlerp(const QUATERNION& p, const QUATERNION& q, T t) { + return normalize(lerp(p, q, t)); + } + + friend inline + constexpr QUATERNION MATH_PURE positive(const QUATERNION& q) { + return q.w < 0 ? -q : q; + } +}; + +} // namespace filament::math::details + +#endif // TNT_MATH_TQUATHELPERS_H diff --git a/package/android/libs/filament/include/math/TVecHelpers.h b/package/android/libs/filament/include/math/TVecHelpers.h new file mode 100644 index 00000000..fb7d026d --- /dev/null +++ b/package/android/libs/filament/include/math/TVecHelpers.h @@ -0,0 +1,654 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TVECHELPERS_H +#define TNT_MATH_TVECHELPERS_H + +#include + +#include // for std:: namespace + +#include +#include + +namespace filament::math::details { + +template +inline constexpr U min(U a, U b) noexcept { + return a < b ? a : b; +} + +template +inline constexpr U max(U a, U b) noexcept { + return a > b ? a : b; +} + +template +struct arithmetic_result { + using type = decltype(std::declval() + std::declval()); +}; + +template +using arithmetic_result_t = typename arithmetic_result::type; + +template +using enable_if_arithmetic_t = std::enable_if_t< + is_arithmetic::value && + is_arithmetic::value && + is_arithmetic::value && + is_arithmetic::value>; + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/vec{2|3|4}.h + */ + +/* + * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments + * operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVec{Add|Product}Operators BASE will automatically + * get all the functionality here. + */ + +template class VECTOR, typename T> +class TVecAddOperators { +public: + /* compound assignment from a another vector of the same size but different + * element type. + */ + template + constexpr VECTOR& operator+=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] += v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator+=(U v) { + return operator+=(VECTOR(v)); + } + + template + constexpr VECTOR& operator-=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] -= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator-=(U v) { + return operator-=(VECTOR(v)); + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + VECTOR> MATH_PURE operator+(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res += rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator+(const VECTOR& lv, U rv) { + return lv + VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator+(U lv, const VECTOR& rv) { + return VECTOR(lv) + rv; + } + + template + friend inline constexpr + VECTOR> MATH_PURE operator-(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res -= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator-(const VECTOR& lv, U rv) { + return lv - VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator-(U lv, const VECTOR& rv) { + return VECTOR(lv) - rv; + } +}; + +template class VECTOR, typename T> +class TVecProductOperators { +public: + /* compound assignment from a another vector of the same size but different + * element type. + */ + template + constexpr VECTOR& operator*=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] *= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator*=(U v) { + return operator*=(VECTOR(v)); + } + + template + constexpr VECTOR& operator/=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] /= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator/=(U v) { + return operator/=(VECTOR(v)); + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + VECTOR> MATH_PURE operator*(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res *= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator*(const VECTOR& lv, U rv) { + return lv * VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator*(U lv, const VECTOR& rv) { + return VECTOR(lv) * rv; + } + + template + friend inline constexpr + VECTOR> MATH_PURE operator/(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res /= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator/(const VECTOR& lv, U rv) { + return lv / VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator/(U lv, const VECTOR& rv) { + return VECTOR(lv) / rv; + } +}; + +/* + * TVecUnaryOperators implements unary operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecUnaryOperators BASE will automatically + * get all the functionality here. + * + * These operators are implemented as friend functions of TVecUnaryOperators + */ +template class VECTOR, typename T> +class TVecUnaryOperators { +public: + constexpr VECTOR operator-() const { + VECTOR r{}; + VECTOR const& rv(static_cast const&>(*this)); + for (size_t i = 0; i < r.size(); i++) { + r[i] = -rv[i]; + } + return r; + } +}; + +/* + * TVecComparisonOperators implements relational/comparison operators + * on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecComparisonOperators BASE will automatically + * get all the functionality here. + */ +template class VECTOR, typename T> +class TVecComparisonOperators { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend inline constexpr + bool MATH_PURE operator==(const VECTOR& lv, const VECTOR& rv) { + for (size_t i = 0; i < lv.size(); i++) { + if (lv[i] != rv[i]) { + return false; + } + } + return true; + } + + template + friend inline constexpr + bool MATH_PURE operator!=(const VECTOR& lv, const VECTOR& rv) { + return !operator==(lv, rv); + } + + template + friend inline constexpr + VECTOR MATH_PURE equal(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] == rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE notEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] != rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE lessThan(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] < rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE lessThanEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] <= rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE greaterThan(const VECTOR& lv, const VECTOR& rv) { + VECTOR r; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] > rv[i]; + } + return r; + } + + template + friend inline + VECTOR MATH_PURE greaterThanEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] >= rv[i]; + } + return r; + } +}; + +/* + * TVecFunctions implements functions on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecFunctions BASE will automatically + * get all the functionality here. + */ +template class VECTOR, typename T> +class TVecFunctions { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend constexpr inline + arithmetic_result_t MATH_PURE dot(const VECTOR& lv, const VECTOR& rv) { + arithmetic_result_t r{}; + for (size_t i = 0; i < lv.size(); i++) { + r += lv[i] * rv[i]; + } + return r; + } + + friend inline T MATH_PURE norm(const VECTOR& lv) { + return std::sqrt(dot(lv, lv)); + } + + friend inline T MATH_PURE length(const VECTOR& lv) { + return norm(lv); + } + + friend inline constexpr T MATH_PURE norm2(const VECTOR& lv) { + return dot(lv, lv); + } + + friend inline constexpr T MATH_PURE length2(const VECTOR& lv) { + return norm2(lv); + } + + template + friend inline constexpr + arithmetic_result_t MATH_PURE distance(const VECTOR& lv, const VECTOR& rv) { + return length(rv - lv); + } + + template + friend inline constexpr + arithmetic_result_t MATH_PURE distance2(const VECTOR& lv, const VECTOR& rv) { + return length2(rv - lv); + } + + friend inline VECTOR MATH_PURE normalize(const VECTOR& lv) { + return lv * (T(1) / length(lv)); + } + + friend inline VECTOR MATH_PURE rcp(VECTOR v) { + return T(1) / v; + } + + friend inline constexpr VECTOR MATH_PURE abs(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < 0 ? -v[i] : v[i]; + } + return v; + } + + friend inline VECTOR MATH_PURE floor(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::floor(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE ceil(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::ceil(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE round(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::round(v[i]); + } + return v; + } + + template + friend inline + VECTOR MATH_PURE fmod(VECTOR const& x, VECTOR const& y) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::fmod(x[i], y[i]); + } + return r; + } + + template + friend inline + VECTOR MATH_PURE remainder(VECTOR const& x, VECTOR const& y) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::remainder(x[i], y[i]); + } + return r; + } + + template + friend inline + VECTOR MATH_PURE remquo(VECTOR const& x, VECTOR const& y, + VECTOR* q) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::remquo(x[i], y[i], &((*q)[i])); + } + return r; + } + + friend inline VECTOR MATH_PURE inversesqrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = T(1) / std::sqrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE sqrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::sqrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE cbrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::cbrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE exp(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::exp(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE sign(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::copysign(T(1), v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE pow(VECTOR v, T p) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::pow(v[i], p); + } + return v; + } + + friend inline VECTOR MATH_PURE pow(T v, VECTOR p) { + for (size_t i = 0; i < p.size(); i++) { + p[i] = std::pow(v, p[i]); + } + return p; + } + + friend inline VECTOR MATH_PURE pow(VECTOR v, VECTOR p) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::pow(v[i], p[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log10(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log10(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log2(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log2(v[i]); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE saturate(const VECTOR& lv) { + return clamp(lv, T(0), T(1)); + } + + friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, T min, T max) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(max, details::max(min, v[i])); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, VECTOR min, VECTOR max) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(max[i], details::max(min[i], v[i])); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE fma(const VECTOR& lv, const VECTOR& rv, + VECTOR a) { + for (size_t i = 0; i < lv.size(); i++) { + a[i] += (lv[i] * rv[i]); + } + return a; + } + + friend inline constexpr VECTOR MATH_PURE min(const VECTOR& u, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(u[i], v[i]); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE max(const VECTOR& u, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::max(u[i], v[i]); + } + return v; + } + + friend inline constexpr T MATH_PURE max(const VECTOR& v) { + T r(v[0]); + for (size_t i = 1; i < v.size(); i++) { + r = max(r, v[i]); + } + return r; + } + + friend inline constexpr T MATH_PURE min(const VECTOR& v) { + T r(v[0]); + for (size_t i = 1; i < v.size(); i++) { + r = min(r, v[i]); + } + return r; + } + + friend inline constexpr VECTOR MATH_PURE mix(const VECTOR& u, VECTOR v, T a) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = u[i] * (T(1) - a) + v[i] * a; + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE smoothstep(T edge0, T edge1, VECTOR v) { + VECTOR t = saturate((v - edge0) / (edge1 - edge0)); + return t * t * (T(3) - T(2) * t); + } + + friend inline constexpr VECTOR MATH_PURE step(T edge, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < edge ? T(0) : T(1); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE step(VECTOR edge, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < edge[i] ? T(0) : T(1); + } + return v; + } + + friend inline constexpr bool MATH_PURE any(const VECTOR& v) { + for (size_t i = 0; i < v.size(); i++) { + if (v[i] != T(0)) return true; + } + return false; + } + + friend inline constexpr bool MATH_PURE all(const VECTOR& v) { + bool result = true; + for (size_t i = 0; i < v.size(); i++) { + result &= (v[i] != T(0)); + } + return result; + } +}; + +} // namespace filament::math::details + +#endif // TNT_MATH_TVECHELPERS_H diff --git a/package/android/libs/filament/include/math/compiler.h b/package/android/libs/filament/include/math/compiler.h new file mode 100644 index 00000000..634e2077 --- /dev/null +++ b/package/android/libs/filament/include/math/compiler.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_MATH_COMPILER_H +#define TNT_MATH_COMPILER_H + +#include + +#if defined (WIN32) + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#ifdef far +#undef far +#endif + +#ifdef near +#undef near +#endif + +#endif + +// compatibility with non-clang compilers... +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__builtin_expect) +# ifdef __cplusplus +# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +# else +# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +# endif +#else +# define MATH_LIKELY( exp ) (exp) +# define MATH_UNLIKELY( exp ) (exp) +#endif + +#if __has_attribute(unused) +# define MATH_UNUSED __attribute__((unused)) +#else +# define MATH_UNUSED +#endif + +#if __has_attribute(pure) +# define MATH_PURE __attribute__((pure)) +#else +# define MATH_PURE +#endif + +#ifdef _MSC_VER +# define MATH_EMPTY_BASES __declspec(empty_bases) + +// MSVC does not support loop unrolling hints +# define MATH_NOUNROLL + +// Sadly, MSVC does not support __builtin_constant_p +# ifndef MAKE_CONSTEXPR +# define MAKE_CONSTEXPR(e) (e) +# endif + +// About value initialization, the C++ standard says: +// if T is a class type with a default constructor that is neither user-provided nor deleted +// (that is, it may be a class with an implicitly-defined or defaulted default constructor), +// the object is zero-initialized and then it is default-initialized +// if it has a non-trivial default constructor; +// Unfortunately, MSVC always calls the default constructor, even if it is trivial, which +// breaks constexpr-ness. To workaround this, we're always zero-initializing TVecN<> +# define MATH_CONSTEXPR_INIT {} +# define MATH_DEFAULT_CTOR {} +# define MATH_DEFAULT_CTOR_CONSTEXPR constexpr +# define CONSTEXPR_IF_NOT_MSVC // when declared constexpr, msvc fails with "failure was caused by cast of object of dynamic type" + +#else // _MSC_VER + +# define MATH_EMPTY_BASES +// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax. +# define MATH_NOUNROLL _Pragma("nounroll") + +# ifndef MAKE_CONSTEXPR +# define MAKE_CONSTEXPR(e) __builtin_constant_p(e) ? (e) : (e) +# endif + +# define MATH_CONSTEXPR_INIT +# define MATH_DEFAULT_CTOR = default; +# define MATH_DEFAULT_CTOR_CONSTEXPR +# define CONSTEXPR_IF_NOT_MSVC constexpr + +#endif // _MSC_VER + +namespace filament::math { + +// MSVC 2019 16.4 doesn't seem to like it when we specialize std::is_arithmetic for +// filament::math::half, so we're forced to create our own is_arithmetic here and specialize it +// inside of half.h. +template +struct is_arithmetic : std::integral_constant::value || std::is_floating_point::value> { +}; + +} // filament::math + +#endif // TNT_MATH_COMPILER_H diff --git a/package/android/libs/filament/include/math/fast.h b/package/android/libs/filament/include/math/fast.h new file mode 100644 index 00000000..85b990d2 --- /dev/null +++ b/package/android/libs/filament/include/math/fast.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_FAST_H +#define TNT_MATH_FAST_H + +#include +#include + +#include +#include + +#include + +#ifdef __ARM_NEON +#include +#endif + +namespace filament { +namespace math { +namespace fast { + +// fast cos(x), ~8 cycles (vs. 66 cycles on ARM) +// can be vectorized +// x between -pi and pi +template::value>> +constexpr T MATH_PURE cos(T x) noexcept { + x *= T(F_1_PI / 2); + x -= T(0.25) + std::floor(x + T(0.25)); + x *= T(16.0) * std::abs(x) - T(8.0); + x += T(0.225) * x * (std::abs(x) - T(1.0)); + return x; +} + +// fast sin(x), ~8 cycles (vs. 66 cycles on ARM) +// can be vectorized +// x between -pi and pi +template::value>> +constexpr T MATH_PURE sin(T x) noexcept { + return filament::math::fast::cos(x - T(F_PI_2)); +} + +constexpr inline float MATH_PURE ilog2(float x) noexcept { + union { + float val; + int32_t x; + } u = { x }; + return float(((u.x >> 23) & 0xff) - 127); +} + +constexpr inline float MATH_PURE log2(float x) noexcept { + union { + float val; + int32_t x; + } u = { x }; + float ilog2 = float(((u.x >> 23) & 0xff) - 128); + u.x = (u.x & 0x007fffff) | 0x3f800000; + return ilog2 + (-0.34484843f * u.val + 2.02466578f) * u.val - 0.67487759f; +} + +// fast 1/sqrt(), on ARMv8 this is 5 cycles vs. 7 cycles, so maybe not worth it. +// we keep this mostly for reference and benchmarking. +inline float MATH_PURE isqrt(float x) noexcept { +#if defined(__ARM_NEON) && defined(__aarch64__) + float y = vrsqrtes_f32(x); + return y * vrsqrtss_f32(x, y * y); +#else + return 1 / std::sqrt(x); +#endif +} + +inline double MATH_PURE isqrt(double x) noexcept { +#if defined(__ARM_NEON) && defined(__aarch64__) + double y = vrsqrted_f64(x); + return y * vrsqrtsd_f64(x, y * y); +#else + return 1 / std::sqrt(x); +#endif +} + +inline int signbit(float x) noexcept { +#if __has_builtin(__builtin_signbitf) + // Note: on Android NDK, signbit() is a function call -- not what we want. + return __builtin_signbitf(x); +#else + return std::signbit(x); +#endif +} + +/* + * constexpr exp(), pow(), factorial() + */ + +constexpr double pow(double x, unsigned int y) noexcept { + return y == 0 ? 1.0 : x * pow(x, y - 1); +} + +constexpr unsigned int factorial(unsigned int x) noexcept { + return x == 0 ? 1 : x * factorial(x - 1); +} + +constexpr double exp(double x) noexcept { + return 1.0 + x + pow(x, 2) / factorial(2) + pow(x, 3) / factorial(3) + + pow(x, 4) / factorial(4) + pow(x, 5) / factorial(5) + + pow(x, 6) / factorial(6) + pow(x, 7) / factorial(7) + + pow(x, 8) / factorial(8) + pow(x, 9) / factorial(9); +} + +constexpr float exp(float x) noexcept { + return float(exp(double(x))); +} + +/* + * unsigned saturated arithmetic + */ + +#if defined(__ARM_NEON) && defined(__aarch64__) +inline uint8_t MATH_PURE qadd(uint8_t a, uint8_t b) noexcept { return vuqaddb_s8(a, b); } +inline uint16_t MATH_PURE qadd(uint16_t a, uint16_t b) noexcept { return vuqaddh_s16(a, b); } +inline uint32_t MATH_PURE qadd(uint32_t a, uint32_t b) noexcept { return vuqadds_s32(a, b); } + +inline uint8_t MATH_PURE qsub(uint8_t a, uint8_t b) noexcept { return vqsubb_s8(a, b); } +inline uint16_t MATH_PURE qsub(uint16_t a, uint16_t b) noexcept { return vqsubh_s16(a, b); } +inline uint32_t MATH_PURE qsub(uint32_t a, uint32_t b) noexcept { return vqsubs_s32(a, b); } +#else + +template::value || + std::is_same::value || + std::is_same::value>> +inline T MATH_PURE qadd(T a, T b) noexcept { + T r = a + b; + return r | -T(r < a); +} + +template::value || + std::is_same::value || + std::is_same::value>> +inline T MATH_PURE qsub(T a, T b) noexcept { + T r = a - b; + return r & -T(r <= a); +} + +#endif + +template +inline T MATH_PURE qinc(T a) noexcept { + return qadd(a, T(1)); +} + +template +inline T MATH_PURE qdec(T a) noexcept { + return qsub(a, T(1)); +} + + +} // namespace fast +} // namespace math +} // namespace filament + +#endif // TNT_MATH_FAST_H diff --git a/package/android/libs/filament/include/math/half.h b/package/android/libs/filament/include/math/half.h new file mode 100644 index 00000000..d792e1bf --- /dev/null +++ b/package/android/libs/filament/include/math/half.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_HALF_H +#define TNT_MATH_HALF_H + +#include + +#include +#include + +#include +#include + +namespace filament { +namespace math { + +template +class fp { + static_assert(S + E + M <= 16, "we only support 16-bits max custom floats"); + + using TYPE = uint16_t; // this should be dynamic + + static constexpr unsigned S_SHIFT = E + M; + static constexpr unsigned E_SHIFT = M; + static constexpr unsigned M_SHIFT = 0; + static constexpr unsigned S_MASK = ((1u << S) - 1u) << S_SHIFT; + static constexpr unsigned E_MASK = ((1u << E) - 1u) << E_SHIFT; + static constexpr unsigned M_MASK = ((1u << M) - 1u) << M_SHIFT; + + struct fp32 { + explicit constexpr fp32(float f) noexcept : fp(f) { } // NOLINT + explicit constexpr fp32(uint32_t b) noexcept : bits(b) { } // NOLINT + constexpr void setS(unsigned int s) noexcept { + bits = uint32_t((bits & 0x7FFFFFFFu) | (s << 31u)); + } + constexpr unsigned int getS() const noexcept { return bits >> 31u; } + constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; } + constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; } + union { + uint32_t bits; + float fp; + }; + }; + +public: + static constexpr fp fromf(float f) noexcept { + fp out; + if (S == 0 && f < 0.0f) { + return out; + } + + fp32 in(f); + unsigned int sign = in.getS(); + in.setS(0); + if (MATH_UNLIKELY(in.getE() == 0xFF)) { // inf or nan + out.setE((1u << E) - 1u); + out.setM(in.getM() ? (1u << (M - 1u)) : 0); + } else { + constexpr fp32 infinity(((1u << E) - 1u) << 23u); // fp infinity in fp32 position + constexpr fp32 magic(((1u << (E - 1u)) - 1u) << 23u); // exponent offset + in.bits &= ~((1u << (22 - M)) - 1u); // erase extra mantissa bits + in.bits += 1u << (22 - M); // rounding + in.fp *= magic.fp; // add exponent offset + in.bits = in.bits < infinity.bits ? in.bits : infinity.bits; + out.bits = uint16_t(in.bits >> (23 - M)); + } + out.setS(sign); + return out; + } + + static constexpr float tof(fp in) noexcept { + constexpr fp32 magic ((0xFE - ((1u << (E - 1u)) - 1u)) << 23u); + constexpr fp32 infnan((0x80 + ((1u << (E - 1u)) - 1u)) << 23u); + fp32 out((in.bits & ((1u << (E + M)) - 1u)) << (23u - M)); + out.fp *= magic.fp; + if (out.fp >= infnan.fp) { + out.bits |= 0xFFu << 23u; + } + out.bits |= (in.bits & S_MASK) << (31u - S_SHIFT); + return out.fp; + } + + TYPE bits{}; + static constexpr size_t getBitCount() noexcept { return S + E + M; } + constexpr fp() noexcept = default; + explicit constexpr fp(TYPE bits) noexcept : bits(bits) { } + constexpr void setS(unsigned int s) noexcept { bits = TYPE((bits & ~S_MASK) | (s << S_SHIFT)); } + constexpr void setE(unsigned int s) noexcept { bits = TYPE((bits & ~E_MASK) | (s << E_SHIFT)); } + constexpr void setM(unsigned int s) noexcept { bits = TYPE((bits & ~M_MASK) | (s << M_SHIFT)); } + constexpr unsigned int getS() const noexcept { return (bits & S_MASK) >> S_SHIFT; } + constexpr unsigned int getE() const noexcept { return (bits & E_MASK) >> E_SHIFT; } + constexpr unsigned int getM() const noexcept { return (bits & M_MASK) >> M_SHIFT; } +}; + +/* + * half-float + * + * 1 5 10 + * +-+------+------------+ + * |s|eee.ee|mm.mmmm.mmmm| + * +-+------+------------+ + * + * minimum (denormal) value: 2^-24 = 5.96e-8 + * minimum (normal) value: 2^-14 = 6.10e-5 + * maximum value: (2 - 2^-10) * 2^15 = 65504 + * + * Integers between 0 and 2048 can be represented exactly + */ + +#ifdef __ARM_NEON + +using half = __fp16; + +inline constexpr uint16_t getBits(half const& h) noexcept { + return MAKE_CONSTEXPR(reinterpret_cast(h)); +} + +inline constexpr half makeHalf(uint16_t bits) noexcept { + return MAKE_CONSTEXPR(reinterpret_cast(bits)); +} + +#else + +class half { + using fp16 = fp<1, 5, 10>; + +public: + half() = default; + constexpr half(float v) noexcept : mBits(fp16::fromf(v)) { } // NOLINT + constexpr operator float() const noexcept { return fp16::tof(mBits); } // NOLINT + +private: + // these are friends, not members (and they're not "private") + friend constexpr uint16_t getBits(half const& h) noexcept { return h.mBits.bits; } + friend constexpr inline half makeHalf(uint16_t bits) noexcept; + + enum Binary { binary }; + explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { } + + fp16 mBits; +}; + +constexpr inline half makeHalf(uint16_t bits) noexcept { + return half(half::binary, bits); +} + +#endif // __ARM_NEON + +inline constexpr half operator""_h(long double v) { + return half( static_cast(v) ); +} + +template<> struct is_arithmetic : public std::true_type {}; + +} // namespace math +} // namespace filament + +namespace std { + +template<> struct is_floating_point : public std::true_type {}; + +// note: this shouldn't be needed (is_floating_point<> is enough) but some version of msvc need it +// This stopped working with MSVC 2019 16.4, so we specialize our own version of is_arithmetic in +// the math::filament namespace (see above). +template<> struct is_arithmetic : public std::true_type {}; + +template<> +class numeric_limits { +public: + typedef filament::math::half type; + + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool has_infinity = true; + static constexpr const bool has_quiet_NaN = true; + static constexpr const bool has_signaling_NaN = false; + static constexpr const float_denorm_style has_denorm = denorm_absent; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const float_round_style round_style = round_indeterminate; + + static constexpr const int digits = 11; + static constexpr const int digits10 = 3; + static constexpr const int max_digits10 = 5; + static constexpr const int radix = 2; + static constexpr const int min_exponent = -13; + static constexpr const int min_exponent10 = -4; + static constexpr const int max_exponent = 16; + static constexpr const int max_exponent10 = 4; + + inline static constexpr type round_error() noexcept { return filament::math::makeHalf(0x3800); } + inline static constexpr type min() noexcept { return filament::math::makeHalf(0x0400); } + inline static constexpr type max() noexcept { return filament::math::makeHalf(0x7bff); } + inline static constexpr type lowest() noexcept { return filament::math::makeHalf(0xfbff); } + inline static constexpr type epsilon() noexcept { return filament::math::makeHalf(0x1400); } + inline static constexpr type infinity() noexcept { return filament::math::makeHalf(0x7c00); } + inline static constexpr type quiet_NaN() noexcept { return filament::math::makeHalf(0x7fff); } + inline static constexpr type denorm_min() noexcept { return filament::math::makeHalf(0x0001); } + inline static constexpr type signaling_NaN() noexcept { return filament::math::makeHalf(0x7dff); } +}; + +} // namespace std + +#endif // TNT_MATH_HALF_H diff --git a/package/android/libs/filament/include/math/mat2.h b/package/android/libs/filament/include/math/mat2.h new file mode 100644 index 00000000..dba9ca47 --- /dev/null +++ b/package/android/libs/filament/include/math/mat2.h @@ -0,0 +1,347 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT2_H +#define TNT_MATH_MAT2_H + +#include +#include +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +/** + * A 2x2 column-major matrix class. + * + * Conceptually a 2x2 matrix is a an array of 2 column vec2: + * + * mat2 m = + * \f$ + * \left( + * \begin{array}{cc} + * m[0] & m[1] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cc} + * m[0][0] & m[1][0] \\ + * m[0][1] & m[1][1] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cc} + * m(0,0) & m(0,1) \\ + * m(1,0) & m(1,1) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec2. + * + */ +template +class MATH_EMPTY_BASES TMat22 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec2 col_type; + typedef TVec2 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /** + * constructors + */ + + /** + * leaves object uninitialized. use with caution. + */ + constexpr explicit TMat22(no_init) noexcept {} + + + /** + * initialize to identity. + * + * \f$ + * \left( + * \begin{array}{cc} + * 1 & 0 \\ + * 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat22() noexcept ; + + /** + * initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{cc} + * v & 0 \\ + * 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat22(U v) noexcept; + + /** + * sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{cc} + * v[0] & 0 \\ + * 0 & v[1] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat22(const TVec2& v) noexcept; + + /** + * construct from another matrix of the same size + */ + template + constexpr explicit TMat22(const TMat22& rhs) noexcept; + + /** + * construct from 2 column vectors. + * + * \f$ + * \left( + * \begin{array}{cc} + * v0 & v1 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat22(const TVec2& v0, const TVec2& v1) noexcept; + + /** construct from 4 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{cc} + * m[0][0] & m[1][0] \\ + * m[0][1] & m[1][1] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, + typename C, typename D> + constexpr explicit TMat22(A m00, B m01, C m10, D m11) noexcept ; + + + struct row_major_init { + template + constexpr explicit row_major_init(A m00, B m01, C m10, D m11) noexcept + : m(m00, m10, m01, m11) {} + + private: + friend TMat22; + TMat22 m; + }; + + constexpr explicit TMat22(row_major_init c) noexcept : TMat22(std::move(c.m)) {} + + /** + * Rotate by radians in the 2D plane + */ + static TMat22 rotate(T radian) noexcept { + TMat22 r(TMat22::NO_INIT); + T c = std::cos(radian); + T s = std::sin(radian); + r[0][0] = c; + r[1][1] = c; + r[0][1] = s; + r[1][0] = -s; + return r; + } + + template + static constexpr TMat22 translation(const TVec2& t) noexcept { + TMat22 r; + r[2] = t; + return r; + } + + template + static constexpr TMat22 scaling(const TVec2& s) noexcept { + return TMat22{ s }; + } + + template + static constexpr TMat22 scaling(A s) noexcept { + return TMat22{ TVec2{ s, s }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat22::TMat22() noexcept + : m_value{ col_type(1, 0), col_type(0, 1) } { +} + +template +template +constexpr TMat22::TMat22(U v) noexcept + : m_value{ col_type(v, 0), col_type(0, v) } { +} + +template +template +constexpr TMat22::TMat22(const TVec2& v) noexcept + : m_value{ col_type(v[0], 0), col_type(0, v[1]) } { +} + +// construct from 4 scalars. Note that the arrangement +// of values in the constructor is the transpose of the matrix +// notation. +template +template +constexpr TMat22::TMat22(A m00, B m01, C m10, D m11) noexcept + : m_value{ col_type(m00, m01), col_type(m10, m11) } { +} + +template +template +constexpr TMat22::TMat22(const TMat22& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 2 column vectors. +template +template +constexpr TMat22::TMat22(const TVec2& v0, const TVec2& v1) noexcept + : m_value{ v0, v1 } { +} + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat22 mat2; +typedef details::TMat22 mat2f; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat22& lhs, + filament::math::details::TMat22& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat22 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[1][0] = t10; + rhs[1][1] = t11; +} +} + +#endif // TNT_MATH_MAT2_H diff --git a/package/android/libs/filament/include/math/mat3.h b/package/android/libs/filament/include/math/mat3.h new file mode 100644 index 00000000..035865fe --- /dev/null +++ b/package/android/libs/filament/include/math/mat3.h @@ -0,0 +1,540 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT3_H +#define TNT_MATH_MAT3_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +/** + * A 3x3 column-major matrix class. + * + * Conceptually a 3x3 matrix is a an array of 3 column vec3: + * + * mat3 m = + * \f$ + * \left( + * \begin{array}{ccc} + * m[0] & m[1] & m[2] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{ccc} + * m[0][0] & m[1][0] & m[2][0] \\ + * m[0][1] & m[1][1] & m[2][1] \\ + * m[0][2] & m[1][2] & m[2][2] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{ccc} + * m(0,0) & m(0,1) & m(0,2) \\ + * m(1,0) & m(1,1) & m(1,2) \\ + * m(2,0) & m(2,1) & m(2,2) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec3. + * + */ +template +class MATH_EMPTY_BASES TMat33 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatTransform, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec3 col_type; + typedef TVec3 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /** + * constructors + */ + + /** + * leaves object uninitialized. use with caution. + */ + constexpr explicit TMat33(no_init) noexcept {} + + + /** + * initialize to identity. + * + * \f$ + * \left( + * \begin{array}{ccc} + * 1 & 0 & 0 \\ + * 0 & 1 & 0 \\ + * 0 & 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat33() noexcept; + + /** + * initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v & 0 & 0 \\ + * 0 & v & 0 \\ + * 0 & 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat33(U v) noexcept; + + /** + * sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v[0] & 0 & 0 \\ + * 0 & v[1] & 0 \\ + * 0 & 0 & v[2] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat33(const TVec3& v) noexcept; + + /** + * construct from another matrix of the same size + */ + template + constexpr explicit TMat33(const TMat33& rhs) noexcept; + + /** + * construct from 3 column vectors. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v0 & v1 & v2 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat33(const TVec3& v0, const TVec3& v1, const TVec3& v2) noexcept; + + /** construct from 9 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{ccc} + * m[0][0] & m[1][0] & m[2][0] \\ + * m[0][1] & m[1][1] & m[2][1] \\ + * m[0][2] & m[1][2] & m[2][2] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> + constexpr explicit TMat33(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept; + + + struct row_major_init { + template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> + constexpr explicit row_major_init(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept + : m(m00, m10, m20, + m01, m11, m21, + m02, m12, m22) {} + + private: + friend TMat33; + TMat33 m; + }; + + constexpr explicit TMat33(row_major_init c) noexcept : TMat33(std::move(c.m)) {} + + /** + * construct from a quaternion + */ + template + constexpr explicit TMat33(const TQuaternion& q) noexcept; + + /** + * orthogonalize only works on matrices of size 3x3 + */ + friend inline + constexpr TMat33 orthogonalize(const TMat33& m) noexcept { + TMat33 ret(TMat33::NO_INIT); + ret[0] = normalize(m[0]); + ret[2] = normalize(cross(ret[0], m[1])); + ret[1] = normalize(cross(ret[2], ret[0])); + return ret; + } + + /** + * Returns a matrix suitable for transforming normals + * + * Note that the inverse-transpose of a matrix is equal to its cofactor matrix divided by its + * determinant: + * + * transpose(inverse(M)) = cof(M) / det(M) + * + * The cofactor matrix is faster to compute than the inverse-transpose, and it can be argued + * that it is a more correct way of transforming normals anyway. Some references from Dale + * Weiler, Nathan Reed, Inigo Quilez, and Eric Lengyel: + * + * - https://github.com/graphitemaster/normals_revisited + * - http://www.reedbeta.com/blog/normals-inverse-transpose-part-1/ + * - https://www.shadertoy.com/view/3s33zj + * - FGED Volume 1, section 1.7.5 "Inverses of Small Matrices" + * - FGED Volume 1, section 3.2.2 "Transforming Normal Vectors" + * + * In "Transforming Normal Vectors", Lengyel notes that there are two types of transformed + * normals: one that uses the transposed adjugate (aka cofactor matrix) and one that uses the + * transposed inverse. He goes on to say that this difference is inconsequential, except when + * mirroring is involved. + * + * @param m the transform applied to vertices + * @return a matrix to apply to normals + * + * @warning normals transformed by this matrix must be normalized + */ + static constexpr TMat33 getTransformForNormals(const TMat33& m) noexcept { + return matrix::cof(m); + } + + /* + * Returns a matrix representing the pose of a virtual camera looking towards -Z in its + * local Y-up coordinate system. "up" defines where the Y axis of the camera's local coordinate + * system is. + */ + template + static TMat33 lookTo(const TVec3& direction, const TVec3& up) noexcept; + + /** + * Packs the tangent frame represented by the specified matrix into a quaternion. + * Reflection is preserved by encoding it as the sign of the w component in the + * resulting quaternion. Since -0 cannot always be represented on the GPU, this + * function computes a bias to ensure values are always either positive or negative, + * never 0. The bias is computed based on the specified storageSize, which defaults + * to 2 bytes, making the resulting quaternion suitable for storage into an SNORM16 + * vector. + */ + static constexpr TQuaternion packTangentFrame( + const TMat33& m, size_t storageSize = sizeof(int16_t)) noexcept; + + template + static constexpr TMat33 translation(const TVec3& t) noexcept { + TMat33 r; + r[2] = t; + return r; + } + + template + static constexpr TMat33 scaling(const TVec3& s) noexcept { + return TMat33{ s }; + } + + template + static constexpr TMat33 scaling(A s) noexcept { + return TMat33{ TVec3{ s }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat33::TMat33() noexcept + : m_value{ + col_type(1, 0, 0), + col_type(0, 1, 0), + col_type(0, 0, 1) } { +} + +template +template +constexpr TMat33::TMat33(U v) noexcept + : m_value{ + col_type(v, 0, 0), + col_type(0, v, 0), + col_type(0, 0, v) } { +} + +template +template +constexpr TMat33::TMat33(const TVec3& v) noexcept + : m_value{ + col_type(v[0], 0, 0), + col_type(0, v[1], 0), + col_type(0, 0, v[2]) } { +} + +// construct from 16 scalars. Note that the arrangement +// of values in the constructor is the transpose of the matrix +// notation. +template +template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> +constexpr TMat33::TMat33(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept + : m_value{ + col_type(m00, m01, m02), + col_type(m10, m11, m12), + col_type(m20, m21, m22) } { +} + +template +template +constexpr TMat33::TMat33(const TMat33& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 3 column vectors. +template +template +constexpr TMat33::TMat33(const TVec3& v0, const TVec3& v1, const TVec3& v2) noexcept + : m_value{ v0, v1, v2 } { +} + +template +template +constexpr TMat33::TMat33(const TQuaternion& q) noexcept : m_value{} { + const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + const U s = n > 0 ? 2 / n : 0; + const U x = s * q.x; + const U y = s * q.y; + const U z = s * q.z; + const U xx = x * q.x; + const U xy = x * q.y; + const U xz = x * q.z; + const U xw = x * q.w; + const U yy = y * q.y; + const U yz = y * q.z; + const U yw = y * q.w; + const U zz = z * q.z; + const U zw = z * q.w; + m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw); // NOLINT + m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw); // NOLINT + m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy); // NOLINT +} + +template +constexpr T dot_tolerance() noexcept; + +template<> +constexpr float dot_tolerance() noexcept { return 0.999f; } + +template<> +constexpr double dot_tolerance() noexcept { return 0.9999; } + +template +template +TMat33 TMat33::lookTo(const TVec3& direction, const TVec3& up) noexcept { + auto const z_axis = direction; + auto norm_up = up; + if (std::abs(dot(z_axis, norm_up)) > dot_tolerance< arithmetic_result_t >()) { + // Fix up vector if we're degenerate (looking straight up, basically) + norm_up = { norm_up.z, norm_up.x, norm_up.y }; + } + auto const x_axis = normalize(cross(z_axis, norm_up)); + auto const y_axis = cross(x_axis, z_axis); + return { x_axis, y_axis, -z_axis }; +} + +//------------------------------------------------------------------------------ +template +constexpr TQuaternion TMat33::packTangentFrame(const TMat33& m, size_t storageSize) noexcept { + TQuaternion q = TMat33{ m[0], cross(m[2], m[0]), m[2] }.toQuaternion(); + q = positive(normalize(q)); + + // Ensure w is never 0.0 + // Bias is 2^(nb_bits - 1) - 1 + const T bias = T(1.0) / T((1 << (storageSize * CHAR_BIT - 1)) - 1); + if (q.w < bias) { + q.w = bias; + + const T factor = (T)(std::sqrt(1.0 - (double)bias * (double)bias)); + q.xyz *= factor; + } + + // If there's a reflection ((n x t) . b <= 0), make sure w is negative + if (dot(cross(m[0], m[2]), m[1]) < T(0)) { + q = -q; + } + + return q; +} + + +} // namespace details + +/** + * Pre-scale a matrix m by the inverse of the largest scale factor to avoid large post-transform + * magnitudes in the shader. This is useful for normal transformations, to avoid large + * post-transform magnitudes in the shader, especially in the fragment shader, where we use + * medium precision. + */ +template +constexpr details::TMat33 prescaleForNormals(const details::TMat33& m) noexcept { + return m * details::TMat33( + 1.0 / std::sqrt(max(float3{length2(m[0]), length2(m[1]), length2(m[2])}))); +} + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat33 mat3; +typedef details::TMat33 mat3f; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat33& lhs, + filament::math::details::TMat33& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat33 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t02 = lhs[0][2]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + const T t12 = lhs[1][2]; + const T t20 = lhs[2][0]; + const T t21 = lhs[2][1]; + const T t22 = lhs[2][2]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[0][2] = rhs[0][2]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + lhs[1][2] = rhs[1][2]; + lhs[2][0] = rhs[2][0]; + lhs[2][1] = rhs[2][1]; + lhs[2][2] = rhs[2][2]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[0][2] = t02; + rhs[1][0] = t10; + rhs[1][1] = t11; + rhs[1][2] = t12; + rhs[2][0] = t20; + rhs[2][1] = t21; + rhs[2][2] = t22; +} +} + +#endif // TNT_MATH_MAT3_H diff --git a/package/android/libs/filament/include/math/mat4.h b/package/android/libs/filament/include/math/mat4.h new file mode 100644 index 00000000..57058539 --- /dev/null +++ b/package/android/libs/filament/include/math/mat4.h @@ -0,0 +1,667 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT4_H +#define TNT_MATH_MAT4_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +template +class TQuaternion; + +/** + * A 4x4 column-major matrix class. + * + * Conceptually a 4x4 matrix is a an array of 4 column double4: + * + * mat4 m = + * \f$ + * \left( + * \begin{array}{cccc} + * m[0] & m[1] & m[2] & m[3] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cccc} + * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\ + * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\ + * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\ + * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cccc} + * m(0,0) & m(0,1) & m(0,2) & m(0,3) \\ + * m(1,0) & m(1,1) & m(1,2) & m(1,3) \\ + * m(2,0) & m(2,1) & m(2,2) & m(2,3) \\ + * m(3,0) & m(3,1) & m(3,2) & m(3,3) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4. + * + */ +template +class MATH_EMPTY_BASES TMat44 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatTransform, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec4 col_type; + typedef TVec4 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /* + * constructors + */ + + // leaves object uninitialized. use with caution. + constexpr explicit TMat44(no_init) noexcept {} + + /** initialize to identity. + * + * \f$ + * \left( + * \begin{array}{cccc} + * 1 & 0 & 0 & 0 \\ + * 0 & 1 & 0 & 0 \\ + * 0 & 0 & 1 & 0 \\ + * 0 & 0 & 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat44() noexcept; + + /** initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v & 0 & 0 & 0 \\ + * 0 & v & 0 & 0 \\ + * 0 & 0 & v & 0 \\ + * 0 & 0 & 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat44(U v) noexcept; + + /** sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v[0] & 0 & 0 & 0 \\ + * 0 & v[1] & 0 & 0 \\ + * 0 & 0 & v[2] & 0 \\ + * 0 & 0 & 0 & v[3] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat44(const TVec4& v) noexcept; + + // construct from another matrix of the same size + template + constexpr explicit TMat44(const TMat44& rhs) noexcept; + + /** construct from 4 column vectors. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v0 & v1 & v2 & v3 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat44(const TVec4& v0, const TVec4& v1, const TVec4& v2, + const TVec4& v3) noexcept; + + /** construct from 16 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{cccc} + * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\ + * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\ + * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\ + * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> + constexpr explicit TMat44(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept; + + + struct row_major_init { + template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> + constexpr explicit row_major_init(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept + : m(m00, m10, m20, m30, + m01, m11, m21, m31, + m02, m12, m22, m32, + m03, m13, m23, m33) {} + + private: + friend TMat44; + TMat44 m; + }; + + constexpr explicit TMat44(row_major_init c) noexcept : TMat44(std::move(c.m)) {} + + /** + * construct from a quaternion + */ + template + constexpr explicit TMat44(const TQuaternion& q) noexcept; + + /** + * construct from a 3x3 matrix + */ + template + constexpr explicit TMat44(const TMat33& matrix) noexcept; + + /** + * construct from a 3x3 matrix and 3d translation + */ + template + constexpr TMat44(const TMat33& matrix, const TVec3& translation) noexcept; + + /** + * construct from a 3x3 matrix and 4d last column. + */ + template + constexpr TMat44(const TMat33& matrix, const TVec4& column3) noexcept; + + static constexpr TMat44 ortho(T left, T right, T bottom, T top, T near, T far) noexcept; + + static constexpr TMat44 frustum(T left, T right, T bottom, T top, T near, T far) noexcept; + + enum class Fov { + HORIZONTAL, + VERTICAL + }; + static TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL) noexcept; + + template + static TMat44 lookAt(const TVec3& eye, const TVec3& center, const TVec3& up) noexcept; + + template + static TMat44 lookTo(const TVec3& direction, const TVec3& position, const TVec3& up) noexcept; + + template + static constexpr TVec3 project(const TMat44& projectionMatrix, TVec3 vertice) noexcept{ + TVec4 r = projectionMatrix * TVec4{ vertice, 1 }; + return TVec3{ r[0], r[1], r[2] } * (1 / r[3]); + } + + template + static constexpr TVec4 project(const TMat44& projectionMatrix, TVec4 vertice) noexcept{ + vertice = projectionMatrix * vertice; + return { TVec3{ vertice[0], vertice[1], vertice[2] } * (1 / vertice[3]), 1 }; + } + + /** + * Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix + */ + inline constexpr TMat33 upperLeft() const noexcept { + const TVec3 v0 = { m_value[0][0], m_value[0][1], m_value[0][2] }; + const TVec3 v1 = { m_value[1][0], m_value[1][1], m_value[1][2] }; + const TVec3 v2 = { m_value[2][0], m_value[2][1], m_value[2][2] }; + return TMat33(v0, v1, v2); + } + + template + static constexpr TMat44 translation(const TVec3& t) noexcept { + TMat44 r; + r[3] = TVec4{ t, 1 }; + return r; + } + + template + static constexpr TMat44 scaling(const TVec3& s) noexcept { + return TMat44{ TVec4{ s, 1 }}; + } + + template + static constexpr TMat44 scaling(A s) noexcept { + return TMat44{ TVec4{ s, s, s, 1 }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat44::TMat44() noexcept + : m_value{ + col_type(1, 0, 0, 0), + col_type(0, 1, 0, 0), + col_type(0, 0, 1, 0), + col_type(0, 0, 0, 1) } { +} + +template +template +constexpr TMat44::TMat44(U v) noexcept + : m_value{ + col_type(v, 0, 0, 0), + col_type(0, v, 0, 0), + col_type(0, 0, v, 0), + col_type(0, 0, 0, v) } { +} + +template +template +constexpr TMat44::TMat44(const TVec4& v) noexcept + : m_value{ + col_type(v[0], 0, 0, 0), + col_type(0, v[1], 0, 0), + col_type(0, 0, v[2], 0), + col_type(0, 0, 0, v[3]) } { +} + + +// construct from 16 scalars +template +template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> +constexpr TMat44::TMat44(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept + : m_value{ + col_type(m00, m01, m02, m03), + col_type(m10, m11, m12, m13), + col_type(m20, m21, m22, m23), + col_type(m30, m31, m32, m33) } { +} + +template +template +constexpr TMat44::TMat44(const TMat44& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 4 column vectors. +template +template +constexpr TMat44::TMat44(const TVec4& v0, const TVec4& v1, + const TVec4& v2, const TVec4& v3) noexcept + : m_value{ v0, v1, v2, v3 } { +} + +template +template +constexpr TMat44::TMat44(const TQuaternion& q) noexcept : m_value{} { + const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + const U s = n > 0 ? 2 / n : 0; + const U x = s * q.x; + const U y = s * q.y; + const U z = s * q.z; + const U xx = x * q.x; + const U xy = x * q.y; + const U xz = x * q.z; + const U xw = x * q.w; + const U yy = y * q.y; + const U yz = y * q.z; + const U yw = y * q.w; + const U zz = z * q.z; + const U zw = z * q.w; + m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw, 0); + m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw, 0); // NOLINT + m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy, 0); // NOLINT + m_value[3] = col_type(0, 0, 0, 1); // NOLINT +} + +template +template +constexpr TMat44::TMat44(const TMat33& m) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(0, 0, 0, 1) } // NOLINT +{ +} + +template +template +constexpr TMat44::TMat44(const TMat33& m, const TVec3& v) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(v[0], v[1], v[2], 1) } // NOLINT +{ +} + +template +template +constexpr TMat44::TMat44(const TMat33& m, const TVec4& v) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(v[0], v[1], v[2], v[3]) } // NOLINT +{ +} + + +// ---------------------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------------------- + +template +constexpr TMat44 TMat44::ortho(T left, T right, T bottom, T top, T near, T far) noexcept { + TMat44 m; + m[0][0] = 2 / (right - left); + m[1][1] = 2 / (top - bottom); + m[2][2] = -2 / (far - near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far - near); + return m; +} + +template +constexpr TMat44 TMat44::frustum(T left, T right, T bottom, T top, T near, T far) noexcept { + TMat44 m; + m[0][0] = (2 * near) / (right - left); + // 0 + // 0 + // 0 + + // 0 + m[1][1] = (2 * near) / (top - bottom); + // 0 + // 0 + + m[2][0] = (right + left) / (right - left); + m[2][1] = (top + bottom) / (top - bottom); + m[2][2] = -(far + near) / (far - near); + m[2][3] = -1; + + // 0 + // 0 + m[3][2] = -(2 * far * near) / (far - near); + m[3][3] = 0; + return m; +} + +template +TMat44 TMat44::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) noexcept { + T h, w; + + if (direction == TMat44::Fov::VERTICAL) { + h = std::tan(fov * F_PI / 360.0f) * near; + w = h * aspect; + } else { + w = std::tan(fov * F_PI / 360.0f) * near; + h = w / aspect; + } + return frustum(-w, w, -h, h, near, far); +} + +/* + * Returns a matrix representing the pose of a virtual camera looking towards -Z in its + * local Y-up coordinate system. "eye" is where the camera is located, "center" is the point it's + * looking at and "up" defines where the Y axis of the camera's local coordinate system is. + */ +template +template +TMat44 TMat44::lookAt(const TVec3& eye, const TVec3& center, + const TVec3& up) noexcept { + return lookTo(normalize(center - eye), eye, normalize(up)); +} + +template +template +TMat44 TMat44::lookTo(const TVec3& direction, const TVec3& position, + const TVec3& up) noexcept { + auto r = TMat33::lookTo(direction, up); + return TMat44{ + TVec4{ r[0], 0 }, + TVec4{ r[1], 0 }, + TVec4{ r[2], 0 }, + TVec4{ position, 1 } }; +} + +// ---------------------------------------------------------------------------------------- +// Arithmetic operators outside of class +// ---------------------------------------------------------------------------------------- + +// mat44 * vec3, result is vec3( mat44 * {vec3, 1} ) +template +constexpr typename TMat44::col_type MATH_PURE operator*(const TMat44& lhs, + const TVec3& rhs) noexcept { + return lhs * TVec4{ rhs, 1 }; +} + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat44 mat4; +typedef details::TMat44 mat4f; + +// mat4 * float4, with double precision intermediates +constexpr float4 highPrecisionMultiply(mat4f const& lhs, float4 const& rhs) noexcept { + double4 result{}; + result += lhs[0] * rhs[0]; + result += lhs[1] * rhs[1]; + result += lhs[2] * rhs[2]; + result += lhs[3] * rhs[3]; + return float4{ result }; +} + +// mat4 * mat4, with double precision intermediates +constexpr mat4f highPrecisionMultiply(mat4f const& lhs, mat4f const& rhs) noexcept { + return { + highPrecisionMultiply(lhs, rhs[0]), + highPrecisionMultiply(lhs, rhs[1]), + highPrecisionMultiply(lhs, rhs[2]), + highPrecisionMultiply(lhs, rhs[3]) + }; +} + +// mat4 * float4, with double precision intermediates +constexpr double4 highPrecisionMultiplyd(mat4f const& lhs, float4 const& rhs) noexcept { + double4 result{}; + result += lhs[0] * rhs[0]; + result += lhs[1] * rhs[1]; + result += lhs[2] * rhs[2]; + result += lhs[3] * rhs[3]; + return result; +} + +// mat4 * mat4, with double precision intermediates +constexpr mat4 highPrecisionMultiplyd(mat4f const& lhs, mat4f const& rhs) noexcept { + return { + highPrecisionMultiplyd(lhs, rhs[0]), + highPrecisionMultiplyd(lhs, rhs[1]), + highPrecisionMultiplyd(lhs, rhs[2]), + highPrecisionMultiplyd(lhs, rhs[3]) + }; +} + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat44& lhs, + filament::math::details::TMat44& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat44 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t02 = lhs[0][2]; + const T t03 = lhs[0][3]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + const T t12 = lhs[1][2]; + const T t13 = lhs[1][3]; + const T t20 = lhs[2][0]; + const T t21 = lhs[2][1]; + const T t22 = lhs[2][2]; + const T t23 = lhs[2][3]; + const T t30 = lhs[3][0]; + const T t31 = lhs[3][1]; + const T t32 = lhs[3][2]; + const T t33 = lhs[3][3]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[0][2] = rhs[0][2]; + lhs[0][3] = rhs[0][3]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + lhs[1][2] = rhs[1][2]; + lhs[1][3] = rhs[1][3]; + lhs[2][0] = rhs[2][0]; + lhs[2][1] = rhs[2][1]; + lhs[2][2] = rhs[2][2]; + lhs[2][3] = rhs[2][3]; + lhs[3][0] = rhs[3][0]; + lhs[3][1] = rhs[3][1]; + lhs[3][2] = rhs[3][2]; + lhs[3][3] = rhs[3][3]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[0][2] = t02; + rhs[0][3] = t03; + rhs[1][0] = t10; + rhs[1][1] = t11; + rhs[1][2] = t12; + rhs[1][3] = t13; + rhs[2][0] = t20; + rhs[2][1] = t21; + rhs[2][2] = t22; + rhs[2][3] = t23; + rhs[3][0] = t30; + rhs[3][1] = t31; + rhs[3][2] = t32; + rhs[3][3] = t33; +} +} + +#endif // TNT_MATH_MAT4_H diff --git a/package/android/libs/filament/include/math/mathfwd.h b/package/android/libs/filament/include/math/mathfwd.h new file mode 100644 index 00000000..b2d3ad84 --- /dev/null +++ b/package/android/libs/filament/include/math/mathfwd.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef TNT_MATH_MATHFWD_H +#define TNT_MATH_MATHFWD_H + +#ifdef _MSC_VER + +// MSVC cannot compute the size of math types correctly when this file is included before the +// actual implementations. +// See github.com/google/filament/issues/2190. +#include +#include +#include +#include +#include +#include + +#else + +#include + +namespace filament::math { +namespace details { + +template class TVec2; +template class TVec3; +template class TVec4; + +template class TMat22; +template class TMat33; +template class TMat44; + +template class TQuaternion; + +} // namespace details + +using double2 = details::TVec2; +using float2 = details::TVec2; +using int2 = details::TVec2; +using uint2 = details::TVec2; +using short2 = details::TVec2; +using ushort2 = details::TVec2; +using byte2 = details::TVec2; +using ubyte2 = details::TVec2; +using bool2 = details::TVec2; + +using double3 = details::TVec3; +using float3 = details::TVec3; +using int3 = details::TVec3; +using uint3 = details::TVec3; +using short3 = details::TVec3; +using ushort3 = details::TVec3; +using byte3 = details::TVec3; +using ubyte3 = details::TVec3; +using bool3 = details::TVec3; + +using double4 = details::TVec4; +using float4 = details::TVec4; +using int4 = details::TVec4; +using uint4 = details::TVec4; +using short4 = details::TVec4; +using ushort4 = details::TVec4; +using byte4 = details::TVec4; +using ubyte4 = details::TVec4; +using bool4 = details::TVec4; + +using mat2 = details::TMat22; +using mat2f = details::TMat22; + +using mat3 = details::TMat33; +using mat3f = details::TMat33; + +using mat4 = details::TMat44; +using mat4f = details::TMat44; + +using quat = details::TQuaternion; +using quatf = details::TQuaternion; + +} // namespace filament::math + +#endif // _MSC_VER + +#endif // TNT_MATH_MATHFWD_H diff --git a/package/android/libs/filament/include/math/norm.h b/package/android/libs/filament/include/math/norm.h new file mode 100644 index 00000000..d4d99ba8 --- /dev/null +++ b/package/android/libs/filament/include/math/norm.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_NORM_H +#define TNT_MATH_NORM_H + +#include +#include + +#include +#include + +namespace filament { +namespace math { + +inline uint16_t packUnorm16(float v) noexcept { + return static_cast(std::round(clamp(v, 0.0f, 1.0f) * 65535.0f)); +} + +inline ushort4 packUnorm16(float4 v) noexcept { + return ushort4{ packUnorm16(v.x), packUnorm16(v.y), packUnorm16(v.z), packUnorm16(v.w) }; +} + +inline int16_t packSnorm16(float v) noexcept { + return static_cast(std::round(clamp(v, -1.0f, 1.0f) * 32767.0f)); +} + +inline short2 packSnorm16(float2 v) noexcept { + return short2{ packSnorm16(v.x), packSnorm16(v.y) }; +} + +inline short4 packSnorm16(float4 v) noexcept { + return short4{ packSnorm16(v.x), packSnorm16(v.y), packSnorm16(v.z), packSnorm16(v.w) }; +} + +inline float unpackUnorm16(uint16_t v) noexcept { + return v / 65535.0f; +} + +inline float4 unpackUnorm16(ushort4 v) noexcept { + return float4{ unpackUnorm16(v.x), unpackUnorm16(v.y), unpackUnorm16(v.z), unpackUnorm16(v.w) }; +} + +inline float unpackSnorm16(int16_t v) noexcept { + return clamp(v / 32767.0f, -1.0f, 1.0f); +} + +inline float4 unpackSnorm16(short4 v) noexcept { + return float4{ unpackSnorm16(v.x), unpackSnorm16(v.y), unpackSnorm16(v.z), unpackSnorm16(v.w) }; +} + +inline uint8_t packUnorm8(float v) noexcept { + return static_cast(std::round(clamp(v, 0.0f, 1.0f) * 255.0)); +} + +inline ubyte4 packUnorm8(float4 v) noexcept { + return ubyte4{ packUnorm8(v.x), packUnorm8(v.y), packUnorm8(v.z), packUnorm8(v.w) }; +} + +inline int8_t packSnorm8(float v) noexcept { + return static_cast(std::round(clamp(v, -1.0f, 1.0f) * 127.0)); +} + +inline byte4 packSnorm8(float4 v) noexcept { + return byte4{ packSnorm8(v.x), packSnorm8(v.y), packSnorm8(v.z), packSnorm8(v.w) }; +} + +inline float unpackUnorm8(uint8_t v) noexcept { + return v / 255.0f; +} + +inline float4 unpackUnorm8(ubyte4 v) noexcept { + return float4{ unpackUnorm8(v.x), unpackUnorm8(v.y), unpackUnorm8(v.z), unpackUnorm8(v.w) }; +} + +inline float unpackSnorm8(int8_t v) noexcept { + return clamp(v / 127.0f, -1.0f, 1.0f); +} + +inline float4 unpackSnorm8(byte4 v) noexcept { + return float4{ unpackSnorm8(v.x), unpackSnorm8(v.y), unpackSnorm8(v.z), unpackSnorm8(v.w) }; +} + +} // namespace math +} // namespace filament + +#endif // TNT_MATH_NORM_H diff --git a/package/android/libs/filament/include/math/quat.h b/package/android/libs/filament/include/math/quat.h new file mode 100644 index 00000000..af9f7467 --- /dev/null +++ b/package/android/libs/filament/include/math/quat.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef TNT_MATH_QUAT_H +#define TNT_MATH_QUAT_H + +#include +#include +#include +#include +#include + +#include +#include + +namespace filament::math { +namespace details { + +template +class MATH_EMPTY_BASES TQuaternion : + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TQuatProductOperators, + public TQuatFunctions { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + + /* + * quaternion internals stored as: + * + * q = w + xi + yj + zk + * + * q[0] = x; + * q[1] = y; + * q[2] = z; + * q[3] = w; + * + */ + union { + struct { T x, y, z, w; }; + TVec4 xyzw; + TVec3 xyz; + TVec2 xy; + }; + + enum { SIZE = 4 }; + inline constexpr static size_type size() { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const { + // only possible in C++0x14 with constexpr + assert(i < SIZE); + return (&x)[i]; + } + + inline constexpr T& operator[](size_t i) { + assert(i < SIZE); + return (&x)[i]; + } + + // ----------------------------------------------------------------------- + // we want the compiler generated versions for these... + TQuaternion(const TQuaternion&) = default; + ~TQuaternion() = default; + TQuaternion& operator=(const TQuaternion&) = default; + + // constructors + + // Leaves object uninitialized. Use with caution. + explicit constexpr TQuaternion(no_init) {} + + // default constructor. sets all values to zero. + constexpr TQuaternion() : x(0), y(0), z(0), w(0) {} + + // Handles implicit conversion to a quat. Must not be explicit. + template> + constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {} // NOLINT(google-explicit-constructor) + + // initialize from 4 values to w + xi + yj + zk + template> + constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) {} + + // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w + template> + constexpr TQuaternion(const TVec3& v, B w) : x(v.x), y(v.y), z(v.z), w(w) {} + + // initialize from a vec4 + template> + constexpr explicit TQuaternion(const TVec4& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} + + // initialize from a quaternion of a different type + template> + constexpr explicit TQuaternion(const TQuaternion& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} + + // conjugate operator + constexpr TQuaternion operator~() const { + return conj(*this); + } + + // constructs a quaternion from an axis and angle + template> + constexpr static TQuaternion MATH_PURE fromAxisAngle(const TVec3& axis, B angle) { + return TQuaternion(std::sin(angle * 0.5) * normalize(axis), std::cos(angle * 0.5)); + } + + // constructs a quaternion from orig to dest. + // it returns the shortest arc and `from` and `to` must be normalized. + template> + constexpr static TQuaternion MATH_PURE fromDirectedRotation(const TVec3& from, const TVec3& to) { + // see the implementation of glm/gtx/quaternion.hpp + T cosTheta = dot(from, to); + TVec3 rotationAxis; + + if (cosTheta >= T(1) - std::numeric_limits::epsilon()) { + // orig and dest point in the same direction + return TQuaternion(1, 0, 0, 0); + } + + if (cosTheta < T(-1) + std::numeric_limits::epsilon()) { + // special case when vectors in opposite directions : + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + // This implementation favors a rotation around the Up axis (Y), + // since it's often what you want to do. + rotationAxis = cross(TVec3(0, 0, 1), from); + + if (length2(rotationAxis) < std::numeric_limits::epsilon()) { + // bad luck, they were parallel, try again! + rotationAxis = cross(TVec3(1, 0, 0), from); + } + + rotationAxis = normalize(rotationAxis); + return fromAxisAngle(rotationAxis, F_PI); + } + + // implementation from Stan Melax's Game Programming Gems 1 article + rotationAxis = cross(from, to); + + const T s = std::sqrt((T(1) + cosTheta) * T(2)); + return TQuaternion(s * T(0.5), + rotationAxis.x / s, rotationAxis.y / s, rotationAxis.z / s); + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TQuaternion quat; +typedef details::TQuaternion quatf; +typedef details::TQuaternion quath; + +// note: don't put a space between "" and _{i,j,k}, this is deprecated + +constexpr inline quat operator ""_i(long double v) { + return { 0.0, double(v), 0.0, 0.0 }; +} + +constexpr inline quat operator ""_j(long double v) { + return { 0.0, 0.0, double(v), 0.0 }; +} + +constexpr inline quat operator ""_k(long double v) { + return { 0.0, 0.0, 0.0, double(v) }; +} + +constexpr inline quat operator ""_i(unsigned long long v) { + return { 0.0, double(v), 0.0, 0.0 }; +} + +constexpr inline quat operator ""_j(unsigned long long v) { + return { 0.0, 0.0, double(v), 0.0 }; +} + +constexpr inline quat operator ""_k(unsigned long long v) { + return { 0.0, 0.0, 0.0, double(v) }; +} + +} // namespace filament::math + +#endif // TNT_MATH_QUAT_H diff --git a/package/android/libs/filament/include/math/scalar.h b/package/android/libs/filament/include/math/scalar.h new file mode 100644 index 00000000..1de77d24 --- /dev/null +++ b/package/android/libs/filament/include/math/scalar.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_SCALAR_H +#define TNT_MATH_SCALAR_H + +#include +#include + +namespace filament { +namespace math { + +constexpr const double F_E = 2.71828182845904523536028747135266250; +constexpr const double F_LOG2E = 1.44269504088896340735992468100189214; +constexpr const double F_LOG10E = 0.434294481903251827651128918916605082; +constexpr const double F_LN2 = 0.693147180559945309417232121458176568; +constexpr const double F_LN10 = 2.30258509299404568401799145468436421; +constexpr const double F_PI = 3.14159265358979323846264338327950288; +constexpr const double F_PI_2 = 1.57079632679489661923132169163975144; +constexpr const double F_PI_4 = 0.785398163397448309615660845819875721; +constexpr const double F_1_PI = 0.318309886183790671537767526745028724; +constexpr const double F_2_PI = 0.636619772367581343075535053490057448; +constexpr const double F_2_SQRTPI = 1.12837916709551257389615890312154517; +constexpr const double F_SQRT2 = 1.41421356237309504880168872420969808; +constexpr const double F_SQRT1_2 = 0.707106781186547524400844362104849039; +constexpr const double F_TAU = 2.0 * F_PI; + +namespace d { +constexpr const double E = F_E; +constexpr const double LOG2E = F_LOG2E; +constexpr const double LOG10E = F_LOG10E; +constexpr const double LN2 = F_LN2; +constexpr const double LN10 = F_LN10; +constexpr const double PI = F_PI; +constexpr const double PI_2 = F_PI_2; +constexpr const double PI_4 = F_PI_4; +constexpr const double ONE_OVER_PI = F_1_PI; +constexpr const double TWO_OVER_PI = F_2_PI; +constexpr const double TWO_OVER_SQRTPI = F_2_SQRTPI; +constexpr const double SQRT2 = F_SQRT2; +constexpr const double SQRT1_2 = F_SQRT1_2; +constexpr const double TAU = F_TAU; +constexpr const double DEG_TO_RAD = F_PI / 180.0; +constexpr const double RAD_TO_DEG = 180.0 / F_PI; +} // namespace d + +namespace f { +constexpr const float E = (float)d::E; +constexpr const float LOG2E = (float)d::LOG2E; +constexpr const float LOG10E = (float)d::LOG10E; +constexpr const float LN2 = (float)d::LN2; +constexpr const float LN10 = (float)d::LN10; +constexpr const float PI = (float)d::PI; +constexpr const float PI_2 = (float)d::PI_2; +constexpr const float PI_4 = (float)d::PI_4; +constexpr const float ONE_OVER_PI = (float)d::ONE_OVER_PI; +constexpr const float TWO_OVER_PI = (float)d::TWO_OVER_PI; +constexpr const float TWO_OVER_SQRTPI = (float)d::TWO_OVER_SQRTPI; +constexpr const float SQRT2 = (float)d::SQRT2; +constexpr const float SQRT1_2 = (float)d::SQRT1_2; +constexpr const float TAU = (float)d::TAU; +constexpr const float DEG_TO_RAD = (float)d::DEG_TO_RAD; +constexpr const float RAD_TO_DEG = (float)d::RAD_TO_DEG; +} // namespace f + +template +inline constexpr T MATH_PURE min(T a, T b) noexcept { + return a < b ? a : b; +} + +template +inline constexpr T MATH_PURE max(T a, T b) noexcept { + return a > b ? a : b; +} + +template +inline constexpr T MATH_PURE clamp(T v, T min, T max) noexcept { + assert(min <= max); + return T(math::min(max, math::max(min, v))); +} + +template +inline constexpr T MATH_PURE saturate(T v) noexcept { + return clamp(v, T(0), T(1)); +} + +template +inline constexpr T MATH_PURE mix(T x, T y, T a) noexcept { + return x * (T(1) - a) + y * a; +} + +template +inline constexpr T MATH_PURE lerp(T x, T y, T a) noexcept { + return mix(x, y, a); +} + +template +inline constexpr T MATH_PURE smoothstep(T e0, T e1, T x) noexcept { + T t = clamp((x - e0) / (e1 - e0), T(0), T(1)); + return t * t * (T(3) - T(2) * t); +} + +template +inline constexpr T sign(T x) noexcept { + return x < T(0) ? T(-1) : T(1); +} + +} // namespace math +} // namespace filament + +#endif // TNT_MATH_SCALAR_H diff --git a/package/android/libs/filament/include/math/vec2.h b/package/android/libs/filament/include/math/vec2.h new file mode 100644 index 00000000..16c11858 --- /dev/null +++ b/package/android/libs/filament/include/math/vec2.h @@ -0,0 +1,114 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC2_H +#define TNT_MATH_VEC2_H + +#include +#include + +#include + +#include +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec2 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 2; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + struct { T x, y; }; + struct { T s, t; }; + struct { T r, g; }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec2() MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec4. must not be explicit. + template> + constexpr TVec2(A v) noexcept : v{ T(v), T(v) } {} + + template> + constexpr TVec2(A x, B y) noexcept : v{ T(x), T(y) } {} + + template> + constexpr TVec2(const TVec2& v) noexcept : v{ T(v[0]), T(v[1]) } {} + + // cross product works only on vectors of size 2 or 3 + template + friend inline constexpr + arithmetic_result_t cross(const TVec2& u, const TVec2& v) noexcept { + return u[0] * v[1] - u[1] * v[0]; + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec2 = details::TVec2; + +using double2 = vec2; +using float2 = vec2; +using half2 = vec2; +using int2 = vec2; +using uint2 = vec2; +using short2 = vec2; +using ushort2 = vec2; +using byte2 = vec2; +using ubyte2 = vec2; +using bool2 = vec2; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC2_H diff --git a/package/android/libs/filament/include/math/vec3.h b/package/android/libs/filament/include/math/vec3.h new file mode 100644 index 00000000..fc856ede --- /dev/null +++ b/package/android/libs/filament/include/math/vec3.h @@ -0,0 +1,133 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC3_H +#define TNT_MATH_VEC3_H + +#include +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec3 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 3; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + TVec2 xy; + TVec2 st; + TVec2 rg; + struct { + union { + T x; + T s; + T r; + }; + union { + struct { T y, z; }; + struct { T t, p; }; + struct { T g, b; }; + TVec2 yz; + TVec2 tp; + TVec2 gb; + }; + }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec3() noexcept MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec3. must not be explicit. + template> + constexpr TVec3(A v) noexcept : v{ T(v), T(v), T(v) } {} + + template> + constexpr TVec3(A x, B y, C z) noexcept : v{ T(x), T(y), T(z) } {} + + template> + constexpr TVec3(const TVec2& v, B z) noexcept : v{ T(v[0]), T(v[1]), T(z) } {} + + template> + constexpr TVec3(const TVec3& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]) } {} + + // cross product works only on vectors of size 3 + template + friend inline constexpr + TVec3> cross(const TVec3& u, const TVec3& v) noexcept { + return { + u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0] }; + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec3 = details::TVec3; + +using double3 = vec3; +using float3 = vec3; +using half3 = vec3; +using int3 = vec3; +using uint3 = vec3; +using short3 = vec3; +using ushort3 = vec3; +using byte3 = vec3; +using ubyte3 = vec3; +using bool3 = vec3; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC3_H diff --git a/package/android/libs/filament/include/math/vec4.h b/package/android/libs/filament/include/math/vec4.h new file mode 100644 index 00000000..77877d5d --- /dev/null +++ b/package/android/libs/filament/include/math/vec4.h @@ -0,0 +1,133 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC4_H +#define TNT_MATH_VEC4_H + +#include +#include + +#include +#include + + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec4 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 4; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + TVec2 xy, st, rg; + TVec3 xyz, stp, rgb; + struct { + union { T x, s, r; }; + union { + TVec2 yz, tp, gb; + TVec3 yzw, tpq, gba; + struct { + union { T y, t, g; }; + union { + TVec2 zw, pq, ba; + struct { T z, w; }; + struct { T p, q; }; + struct { T b, a; }; + }; + }; + }; + }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec4() noexcept MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec4. must not be explicit. + template> + constexpr TVec4(A v) noexcept : v{ T(v), T(v), T(v), T(v) } {} + + template> + constexpr TVec4(A x, B y, C z, D w) noexcept : v{ T(x), T(y), T(z), T(w) } {} + + template> + constexpr TVec4(const TVec2& v, B z, C w) noexcept : v{ T(v[0]), T(v[1]), T(z), T(w) } {} + + template> + constexpr TVec4(const TVec2& v, const TVec2& w) noexcept : v{ + T(v[0]), T(v[1]), T(w[0]), T(w[1]) } {} + + template> + constexpr TVec4(const TVec3& v, B w) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(w) } {} + + template> + constexpr TVec4(const TVec4& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(v[3]) } {} +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec4 = details::TVec4; + +using double4 = vec4; +using float4 = vec4; +using half4 = vec4; +using int4 = vec4; +using uint4 = vec4; +using short4 = vec4; +using ushort4 = vec4; +using byte4 = vec4; +using ubyte4 = vec4; +using bool4 = vec4; + + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC4_H diff --git a/package/android/libs/filament/include/mathio/ostream.h b/package/android/libs/filament/include/mathio/ostream.h new file mode 100644 index 00000000..5628e7c8 --- /dev/null +++ b/package/android/libs/filament/include/mathio/ostream.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if __has_attribute(visibility) +# define MATHIO_PUBLIC __attribute__((visibility("default"))) +#else +# define MATHIO_PUBLIC +#endif + +namespace filament::math::details { + +template class TQuaternion; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec2& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec3& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec4& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat22& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat33& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat44& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TQuaternion& v) noexcept; + +} // namespace filament::math::details diff --git a/package/android/libs/filament/include/mikktspace/mikktspace.h b/package/android/libs/filament/include/mikktspace/mikktspace.h new file mode 100644 index 00000000..52c44a71 --- /dev/null +++ b/package/android/libs/filament/include/mikktspace/mikktspace.h @@ -0,0 +1,145 @@ +/** \file mikktspace/mikktspace.h + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef __MIKKTSPACE_H__ +#define __MIKKTSPACE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Author: Morten S. Mikkelsen + * Version: 1.0 + * + * The files mikktspace.h and mikktspace.c are designed to be + * stand-alone files and it is important that they are kept this way. + * Not having dependencies on structures/classes/libraries specific + * to the program, in which they are used, allows them to be copied + * and used as is into any tool, program or plugin. + * The code is designed to consistently generate the same + * tangent spaces, for a given mesh, in any tool in which it is used. + * This is done by performing an internal welding step and subsequently an order-independent evaluation + * of tangent space for meshes consisting of triangles and quads. + * This means faces can be received in any order and the same is true for + * the order of vertices of each face. The generated result will not be affected + * by such reordering. Additionally, whether degenerate (vertices or texture coordinates) + * primitives are present or not will not affect the generated results either. + * Once tangent space calculation is done the vertices of degenerate primitives will simply + * inherit tangent space from neighboring non degenerate primitives. + * The analysis behind this implementation can be found in my master's thesis + * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/package/android/libs/filament/include/tsl/robin_growth_policy.h b/package/android/libs/filament/include/tsl/robin_growth_policy.h new file mode 100644 index 00000000..daf6bf56 --- /dev/null +++ b/package/android/libs/filament/include/tsl/robin_growth_policy.h @@ -0,0 +1,290 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_GROWTH_POLICY_H +#define TSL_ROBIN_GROWTH_POLICY_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __EXCEPTIONS +# define THROW(_e, _m) throw _e(_m) +#else +# include +# ifndef NDEBUG +# define THROW(_e, _m) do { fprintf(stderr, _m); std::terminate(); } while(0) +# else +# define THROW(_e, _m) std::terminate() +# endif +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__builtin_expect) +# define TSL_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +#else +# define TSL_LIKELY( exp ) (exp) +#endif + +namespace tsl { +namespace rh { + +/** + * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows + * the table to use a mask operation instead of a modulo operation to map a hash to a bucket. + * + * GrowthFactor must be a power of two >= 2. + */ +template +class power_of_two_growth_policy { +public: + /** + * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter. + * This number is a minimum, the policy may update this value with a higher value if needed (but not lower). + */ + power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) { + if(min_bucket_count_in_out > max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + static_assert(MIN_BUCKETS_SIZE > 0, "MIN_BUCKETS_SIZE must be > 0."); + const std::size_t min_bucket_count = MIN_BUCKETS_SIZE; + + min_bucket_count_in_out = std::max(min_bucket_count, min_bucket_count_in_out); + min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out); + m_mask = min_bucket_count_in_out - 1; + } + + /** + * Return the bucket [0, bucket_count()) to which the hash belongs. + */ + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash & m_mask; + } + + /** + * Return the bucket count to use when the bucket array grows on rehash. + */ + std::size_t next_bucket_count() const { + if((m_mask + 1) > max_bucket_count() / GrowthFactor) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + return (m_mask + 1) * GrowthFactor; + } + + /** + * Return the maximum number of buckets supported by the policy. + */ + std::size_t max_bucket_count() const { + // Largest power of two. + return (std::numeric_limits::max() / 2) + 1; + } + +private: + static std::size_t round_up_to_power_of_two(std::size_t value) { + if(is_power_of_two(value)) { + return value; + } + + if(value == 0) { + return 1; + } + + --value; + for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { + value |= value >> i; + } + + return value + 1; + } + + static constexpr bool is_power_of_two(std::size_t value) { + return value != 0 && (value & (value - 1)) == 0; + } + +protected: + static const std::size_t MIN_BUCKETS_SIZE = 2; + static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2."); + + std::size_t m_mask; +}; + + +/** + * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash + * to a bucket. Slower but it can be usefull if you want a slower growth. + */ +template> +class mod_growth_policy { +public: + mod_growth_policy(std::size_t& min_bucket_count_in_out) { + if(min_bucket_count_in_out > max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + static_assert(MIN_BUCKETS_SIZE > 0, "MIN_BUCKETS_SIZE must be > 0."); + const std::size_t min_bucket_count = MIN_BUCKETS_SIZE; + + min_bucket_count_in_out = std::max(min_bucket_count, min_bucket_count_in_out); + m_bucket_count = min_bucket_count_in_out; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash % m_bucket_count; + } + + std::size_t next_bucket_count() const { + if(m_bucket_count == max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + const double next_bucket_count = std::ceil(double(m_bucket_count) * REHASH_SIZE_MULTIPLICATION_FACTOR); + if(!std::isnormal(next_bucket_count)) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + if(next_bucket_count > double(max_bucket_count())) { + return max_bucket_count(); + } + else { + return std::size_t(next_bucket_count); + } + } + + std::size_t max_bucket_count() const { + return MAX_BUCKET_COUNT; + } + +private: + static const std::size_t MIN_BUCKETS_SIZE = 2; + static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den; + static const std::size_t MAX_BUCKET_COUNT = + std::size_t(double( + std::numeric_limits::max() / REHASH_SIZE_MULTIPLICATION_FACTOR + )); + + static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1."); + + std::size_t m_bucket_count; +}; + + + +namespace detail { + +static constexpr const std::array PRIMES = {{ + 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul, 1543ul, 2053ul, + 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, + 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, + 1610612741ul, 3221225473ul, 4294967291ul +}}; + +template +static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; } + +// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the +// compiler can optimize the modulo code better with a constant known at the compilation. +static constexpr const std::array MOD_PRIME = {{ + &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, + &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, + &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, + &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38> +}}; + +} + +/** + * Grow the hash table by using prime numbers as bucket count. Slower than tsl::rh::power_of_two_growth_policy in + * general but will probably distribute the values around better in the buckets with a poor hash function. + * + * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers. + * + * With a switch the code would look like: + * \code + * switch(iprime) { // iprime is the current prime of the hash table + * case 0: hash % 5ul; + * break; + * case 1: hash % 17ul; + * break; + * case 2: hash % 29ul; + * break; + * ... + * } + * \endcode + * + * Due to the constant variable in the modulo the compiler is able to optimize the operation + * by a series of multiplications, substractions and shifts. + * + * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement. + */ +class prime_growth_policy { +public: + prime_growth_policy(std::size_t& min_bucket_count_in_out) { + auto it_prime = std::lower_bound(detail::PRIMES.begin(), + detail::PRIMES.end(), min_bucket_count_in_out); + if(it_prime == detail::PRIMES.end()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + m_iprime = static_cast(std::distance(detail::PRIMES.begin(), it_prime)); + min_bucket_count_in_out = *it_prime; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return detail::MOD_PRIME[m_iprime](hash); + } + + std::size_t next_bucket_count() const { + if(m_iprime + 1 >= detail::PRIMES.size()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + return detail::PRIMES[m_iprime + 1]; + } + + std::size_t max_bucket_count() const { + return detail::PRIMES.back(); + } + +private: + unsigned int m_iprime; + + static_assert(std::numeric_limits::max() >= detail::PRIMES.size(), + "The type of m_iprime is not big enough."); +}; + +} +} + +#endif diff --git a/package/android/libs/filament/include/tsl/robin_hash.h b/package/android/libs/filament/include/tsl/robin_hash.h new file mode 100644 index 00000000..0f94a07a --- /dev/null +++ b/package/android/libs/filament/include/tsl/robin_hash.h @@ -0,0 +1,1252 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_HASH_H +#define TSL_ROBIN_HASH_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "robin_growth_policy.h" + + + +#ifndef tsl_assert + #ifdef TSL_DEBUG + #define tsl_assert(expr) assert(expr) + #else + #define tsl_assert(expr) (static_cast(0)) + #endif +#endif + + + +namespace tsl { + +namespace detail_robin_hash { + +template +struct make_void { + using type = void; +}; + +template +struct has_is_transparent: std::false_type { +}; + +template +struct has_is_transparent::type>: std::true_type { +}; + +template +struct is_power_of_two_policy: std::false_type { +}; + +template +struct is_power_of_two_policy>: std::true_type { +}; + + + +using truncated_hash_type = std::uint_least32_t; + +/** + * Helper class that store a truncated hash if StoreHash is true and nothing otherwise. + */ +template +class bucket_entry_hash { +public: + bool bucket_hash_equal(std::size_t /*hash*/) const noexcept { + return true; + } + + truncated_hash_type truncated_hash() const noexcept { + return 0; + } + +protected: + void set_hash(truncated_hash_type /*hash*/) noexcept { + } +}; + +template<> +class bucket_entry_hash { +public: + bool bucket_hash_equal(std::size_t hash) const noexcept { + return m_hash == truncated_hash_type(hash); + } + + truncated_hash_type truncated_hash() const noexcept { + return m_hash; + } + +protected: + void set_hash(truncated_hash_type hash) noexcept { + m_hash = truncated_hash_type(hash); + } + +private: + truncated_hash_type m_hash; +}; + + +/** + * Each bucket entry has: + * - A value of type `ValueType`. + * - An integer to store how far the value of the bucket, if any, is from its ideal bucket + * (ex: if the current bucket 5 has the value 'foo' and `hash('foo') % nb_buckets` == 3, + * `dist_from_ideal_bucket()` will return 2 as the current value of the bucket is two + * buckets away from its ideal bucket) + * If there is no value in the bucket (i.e. `empty()` is true) `dist_from_ideal_bucket()` will be < 0. + * - A marker which tells us if the bucket is the last bucket of the bucket array (useful for the + * iterator of the hash table). + * - If `StoreHash` is true, 32 bits of the hash of the value, if any, are also stored in the bucket. + * If the size of the hash is more than 32 bits, it is truncated. We don't store the full hash + * as storing the hash is a potential opportunity to use the unused space due to the alignement + * of the bucket_entry structure. We can thus potentially store the hash without any extra space + * (which would not be possible with 64 bits of the hash). + */ +template +class bucket_entry: public bucket_entry_hash { + using bucket_hash = bucket_entry_hash; + +public: + using value_type = ValueType; + using distance_type = std::int_least16_t; + + + bucket_entry() noexcept: bucket_hash(), m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(false) + { + tsl_assert(empty()); + } + + bucket_entry(const bucket_entry& other) noexcept(std::is_nothrow_copy_constructible::value): + bucket_hash(other), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) + { + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(other.value()); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + } + + /** + * Never really used, but still necessary as we must call resize on an empty `std::vector`. + * and we need to support move-only types. See robin_hash constructor for details. + */ + bucket_entry(bucket_entry&& other) noexcept(std::is_nothrow_move_constructible::value): + bucket_hash(std::move(other)), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) + { + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(std::move(other.value())); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + } + + bucket_entry& operator=(const bucket_entry& other) + noexcept(std::is_nothrow_copy_constructible::value) + { + if(this != &other) { + clear(); + + bucket_hash::operator=(other); + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(other.value()); + } + + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + m_last_bucket = other.m_last_bucket; + } + + return *this; + } + + bucket_entry& operator=(bucket_entry&& ) = delete; + + ~bucket_entry() noexcept { + clear(); + } + + void clear() noexcept { + if(!empty()) { + destroy_value(); + m_dist_from_ideal_bucket = EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + } + + bool empty() const noexcept { + return m_dist_from_ideal_bucket == EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + + value_type& value() noexcept { + tsl_assert(!empty()); + return *reinterpret_cast(std::addressof(m_value)); + } + + const value_type& value() const noexcept { + tsl_assert(!empty()); + return *reinterpret_cast(std::addressof(m_value)); + } + + distance_type dist_from_ideal_bucket() const noexcept { + return m_dist_from_ideal_bucket; + } + + bool last_bucket() const noexcept { + return m_last_bucket; + } + + void set_as_last_bucket() noexcept { + m_last_bucket = true; + } + + template + void set_value_of_empty_bucket(distance_type dist_from_ideal_bucket, + truncated_hash_type hash, Args&&... value_type_args) + { + tsl_assert(dist_from_ideal_bucket >= 0); + tsl_assert(empty()); + + ::new (static_cast(std::addressof(m_value))) value_type(std::forward(value_type_args)...); + this->set_hash(hash); + m_dist_from_ideal_bucket = dist_from_ideal_bucket; + + tsl_assert(!empty()); + } + + void swap_with_value_in_bucket(distance_type& dist_from_ideal_bucket, + truncated_hash_type& hash, value_type& value) + { + tsl_assert(!empty()); + + using std::swap; + swap(value, this->value()); + swap(dist_from_ideal_bucket, m_dist_from_ideal_bucket); + + // Avoid warning of unused variable if StoreHash is false + (void) hash; + if(StoreHash) { + const truncated_hash_type tmp_hash = this->truncated_hash(); + this->set_hash(hash); + hash = tmp_hash; + } + } + + static truncated_hash_type truncate_hash(std::size_t hash) noexcept { + return truncated_hash_type(hash); + } + +private: + void destroy_value() noexcept { + tsl_assert(!empty()); + value().~value_type(); + } + +private: + using storage = typename std::aligned_storage::type; + + static const distance_type EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET = -1; + + distance_type m_dist_from_ideal_bucket; + bool m_last_bucket; + storage m_value; +}; + + + +/** + * Internal common class used by `robin_map` and `robin_set`. + * + * ValueType is what will be stored by `robin_hash` (usually `std::pair` for map and `Key` for set). + * + * `KeySelect` should be a `FunctionObject` which takes a `ValueType` in parameter and returns a + * reference to the key. + * + * `ValueSelect` should be a `FunctionObject` which takes a `ValueType` in parameter and returns a + * reference to the value. `ValueSelect` should be void if there is no value (in a set for example). + * + * The strong exception guarantee only holds if the expression + * `std::is_nothrow_swappable::value && std::is_nothrow_move_constructible::value` is true. + * + * Behaviour is undefined if the destructor of `ValueType` throws. + */ +template +class robin_hash: private Hash, private KeyEqual, private GrowthPolicy { +private: + template + using has_mapped_type = typename std::integral_constant::value>; + + +public: + template + class robin_iterator; + + using key_type = typename KeySelect::key_type; + using value_type = ValueType; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = robin_iterator; + using const_iterator = robin_iterator; + + +private: + /** + * Either store the hash because we are asked by the `StoreHash` template parameter + * or store the hash because it doesn't cost us anything in size and can be used to speed up rehash. + */ + static constexpr bool STORE_HASH = StoreHash || + ( + (sizeof(tsl::detail_robin_hash::bucket_entry) == + sizeof(tsl::detail_robin_hash::bucket_entry)) + && + (sizeof(std::size_t) == sizeof(truncated_hash_type) || + is_power_of_two_policy::value) + && + // Don't store the hash for primitive types with default hash. + (!std::is_arithmetic::value || + !std::is_same>::value) + ); + + /** + * Only use the stored hash on lookup if we are explictly asked. We are not sure how slow + * the KeyEqual operation is. An extra comparison may slow things down with a fast KeyEqual. + */ + static constexpr bool USE_STORED_HASH_ON_LOOKUP = StoreHash; + + /** + * We can only use the hash on rehash if the size of the hash type is the same as the stored one or + * if we use a power of two modulo. In the case of the power of two modulo, we just mask + * the least significant bytes, we just have to check that the truncated_hash_type didn't truncated + * more bytes. + */ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#endif + + static bool USE_STORED_HASH_ON_REHASH(size_type bucket_count) { + (void) bucket_count; + if(STORE_HASH && sizeof(std::size_t) == sizeof(truncated_hash_type)) { + return true; + } + else if(STORE_HASH && is_power_of_two_policy::value) { + tsl_assert(bucket_count > 0); + return (bucket_count - 1) <= std::numeric_limits::max(); + } + else { + return false; + } + } + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + using bucket_entry = tsl::detail_robin_hash::bucket_entry; + using distance_type = typename bucket_entry::distance_type; + + using buckets_allocator = typename std::allocator_traits::template rebind_alloc; + using buckets_container_type = std::vector; + + +public: + /** + * The 'operator*()' and 'operator->()' methods return a const reference and const pointer respectively to the + * stored value type. + * + * In case of a map, to get a mutable reference to the value associated to a key (the '.second' in the + * stored pair), you have to call 'value()'. + * + * The main reason for this is that if we returned a `std::pair&` instead + * of a `const std::pair&`, the user may modify the key which will put the map in a undefined state. + */ + template + class robin_iterator { + friend class robin_hash; + + private: + using iterator_bucket = typename std::conditional::type; + + + robin_iterator(iterator_bucket it) noexcept: m_iterator(it) { + } + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const typename robin_hash::value_type; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + + + robin_iterator() noexcept { + } + + robin_iterator(const robin_iterator& other) noexcept: m_iterator(other.m_iterator) { + } + + const typename robin_hash::key_type& key() const { + return KeySelect()(m_iterator->value()); + } + + template::value && IsConst>::type* = nullptr> + const typename U::value_type& value() const { + return U()(m_iterator->value()); + } + + template::value && !IsConst>::type* = nullptr> + typename U::value_type& value() { + return U()(m_iterator->value()); + } + + reference operator*() const { + return m_iterator->value(); + } + + pointer operator->() const { + return std::addressof(m_iterator->value()); + } + + robin_iterator& operator++() { + while(true) { + if(m_iterator->last_bucket()) { + ++m_iterator; + return *this; + } + + ++m_iterator; + if(!m_iterator->empty()) { + return *this; + } + } + } + + robin_iterator operator++(int) { + robin_iterator tmp(*this); + ++*this; + + return tmp; + } + + friend bool operator==(const robin_iterator& lhs, const robin_iterator& rhs) { + return lhs.m_iterator == rhs.m_iterator; + } + + friend bool operator!=(const robin_iterator& lhs, const robin_iterator& rhs) { + return !(lhs == rhs); + } + + private: + iterator_bucket m_iterator; + }; + + +public: + robin_hash(size_type bucket_count, + const Hash& hash, + const KeyEqual& equal, + const Allocator& alloc, + float max_load_factor): Hash(hash), KeyEqual(equal), + // We need a non-zero bucket_count + GrowthPolicy(bucket_count == 0?++bucket_count:bucket_count), + m_buckets(alloc), + m_bucket_count(bucket_count), + m_nb_elements(0), + m_grow_on_next_insert(false) + { + if(bucket_count > max_bucket_count()) { + THROW(std::length_error, "The map exceeds its maxmimum size."); + } + + /* + * We can't use the `vector(size_type count, const Allocator& alloc)` constructor + * as it's only available in C++14 and we need to support C++11. We thus must resize after using + * the `vector(const Allocator& alloc)` constructor. + * + * We can't use `vector(size_type count, const T& value, const Allocator& alloc)` as it requires the + * value T to be copyable. + */ + m_buckets.resize(m_bucket_count); + + tsl_assert(!m_buckets.empty()); + m_buckets.back().set_as_last_bucket(); + + + this->max_load_factor(max_load_factor); + } + + robin_hash(const robin_hash& other) = default; + + robin_hash(robin_hash&& other) noexcept(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value) + : Hash(std::move(static_cast(other))), + KeyEqual(std::move(static_cast(other))), + GrowthPolicy(std::move(static_cast(other))), + m_buckets(std::move(other.m_buckets)), + m_bucket_count(other.m_bucket_count), + m_nb_elements(other.m_nb_elements), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + other.clear(); + } + + robin_hash& operator=(const robin_hash& other) = default; + + robin_hash& operator=(robin_hash&& other) { + other.swap(*this); + other.clear(); + + return *this; + } + + allocator_type get_allocator() const { + return m_buckets.get_allocator(); + } + + + /* + * Iterators + */ + iterator begin() noexcept { + auto begin = m_buckets.begin(); + while(begin != m_buckets.end() && begin->empty()) { + ++begin; + } + + return iterator(begin); + } + + const_iterator begin() const noexcept { + return cbegin(); + } + + const_iterator cbegin() const noexcept { + auto begin = m_buckets.cbegin(); + while(begin != m_buckets.cend() && begin->empty()) { + ++begin; + } + + return const_iterator(begin); + } + + iterator end() noexcept { + return iterator(m_buckets.end()); + } + + const_iterator end() const noexcept { + return cend(); + } + + const_iterator cend() const noexcept { + return const_iterator(m_buckets.cend()); + } + + + /* + * Capacity + */ + bool empty() const noexcept { + return m_nb_elements == 0; + } + + size_type size() const noexcept { + return m_nb_elements; + } + + size_type max_size() const noexcept { + return m_buckets.max_size(); + } + + /* + * Modifiers + */ + void clear() noexcept { + for(auto& bucket: m_buckets) { + bucket.clear(); + } + + m_nb_elements = 0; + m_grow_on_next_insert = false; + } + + + + template + std::pair insert(P&& value) { + return insert_impl(KeySelect()(value), std::forward

(value)); + } + + template + iterator insert(const_iterator hint, P&& value) { + if(hint != cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) { + return mutable_iterator(hint); + } + + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + if(std::is_base_of::iterator_category>::value) + { + const auto nb_elements_insert = std::distance(first, last); + const size_type nb_free_buckets = m_load_threshold - size(); + tsl_assert(m_load_threshold >= size()); + + if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) { + reserve(size() + size_type(nb_elements_insert)); + } + } + + for(; first != last; ++first) { + insert(*first); + } + } + + + + template + std::pair insert_or_assign(K&& key, M&& obj) { + auto it = try_emplace(std::forward(key), std::forward(obj)); + if(!it.second) { + it.first.value() = std::forward(obj); + } + + return it; + } + + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + auto it = mutable_iterator(hint); + it.value() = std::forward(obj); + + return it; + } + + return insert_or_assign(std::forward(key), std::forward(obj)).first; + } + + + template + std::pair emplace(Args&&... args) { + return insert(value_type(std::forward(args)...)); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return insert(hint, value_type(std::forward(args)...)); + } + + + + template + std::pair try_emplace(K&& key, Args&&... args) { + return insert_impl(key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); + } + + template + iterator try_emplace(const_iterator hint, K&& key, Args&&... args) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + return mutable_iterator(hint); + } + + return try_emplace(std::forward(key), std::forward(args)...).first; + } + + /** + * Here to avoid `template size_type erase(const K& key)` being used when + * we use a iterator instead of a const_iterator. + */ + iterator erase(iterator pos) { + erase_from_bucket(pos); + + /** + * Erase bucket used a backward shift after clearing the bucket. + * Check if there is a new value in the bucket, if not get the next non-empty. + */ + if(pos.m_iterator->empty()) { + ++pos; + } + + return pos; + } + + iterator erase(const_iterator pos) { + return erase(mutable_iterator(pos)); + } + + iterator erase(const_iterator first, const_iterator last) { + if(first == last) { + return mutable_iterator(first); + } + + auto first_mutable = mutable_iterator(first); + auto last_mutable = mutable_iterator(last); + for(auto it = first_mutable.m_iterator; it != last_mutable.m_iterator; ++it) { + if(!it->empty()) { + it->clear(); + m_nb_elements--; + } + } + + if(last_mutable == end()) { + return end(); + } + + + /* + * Backward shift on the values which come after the deleted values. + * We try to move the values closer to their ideal bucket. + */ + std::size_t icloser_bucket = std::size_t(std::distance(m_buckets.begin(), first_mutable.m_iterator)); + std::size_t ito_move_closer_value = std::size_t(std::distance(m_buckets.begin(), last_mutable.m_iterator)); + tsl_assert(ito_move_closer_value > icloser_bucket); + + const std::size_t ireturn_bucket = ito_move_closer_value - + std::min(ito_move_closer_value - icloser_bucket, + std::size_t(m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + while(ito_move_closer_value < m_buckets.size() && m_buckets[ito_move_closer_value].dist_from_ideal_bucket() > 0) { + icloser_bucket = ito_move_closer_value - + std::min(ito_move_closer_value - icloser_bucket, + std::size_t(m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + + tsl_assert(m_buckets[icloser_bucket].empty()); + const distance_type new_distance = distance_type(m_buckets[ito_move_closer_value].dist_from_ideal_bucket() - + (ito_move_closer_value - icloser_bucket)); + m_buckets[icloser_bucket].set_value_of_empty_bucket(new_distance, + m_buckets[ito_move_closer_value].truncated_hash(), + std::move(m_buckets[ito_move_closer_value].value())); + m_buckets[ito_move_closer_value].clear(); + + + ++icloser_bucket; + ++ito_move_closer_value; + } + + + return iterator(m_buckets.begin() + ireturn_bucket); + } + + + template + size_type erase(const K& key) { + return erase(key, hash_key(key)); + } + + template + size_type erase(const K& key, std::size_t hash) { + auto it = find(key, hash); + if(it != end()) { + erase_from_bucket(it); + + return 1; + } + else { + return 0; + } + } + + + + + + void swap(robin_hash& other) { + using std::swap; + + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(m_buckets, other.m_buckets); + swap(m_bucket_count, other.m_bucket_count); + swap(m_nb_elements, other.m_nb_elements); + swap(m_load_threshold, other.m_load_threshold); + swap(m_max_load_factor, other.m_max_load_factor); + swap(m_grow_on_next_insert, other.m_grow_on_next_insert); + } + + + /* + * Lookup + */ + template::value>::type* = nullptr> + typename U::value_type& at(const K& key) { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + typename U::value_type& at(const K& key, std::size_t hash) { + return const_cast(static_cast(this)->at(key, hash)); + } + + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key) const { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key, std::size_t hash) const { + auto it = find(key, hash); + if(it != cend()) { + return it.value(); + } + else { + THROW(std::out_of_range, "Couldn't find key."); + } + } + + template::value>::type* = nullptr> + typename U::value_type& operator[](K&& key) { + return try_emplace(std::forward(key)).first.value(); + } + + + template + size_type count(const K& key) const { + return count(key, hash_key(key)); + } + + template + size_type count(const K& key, std::size_t hash) const { + if(find(key, hash) != cend()) { + return 1; + } + else { + return 0; + } + } + + + template + iterator find(const K& key) { + return find_impl(key, hash_key(key)); + } + + template + iterator find(const K& key, std::size_t hash) { + return find_impl(key, hash); + } + + + template + const_iterator find(const K& key) const { + return find_impl(key, hash_key(key)); + } + + template + const_iterator find(const K& key, std::size_t hash) const { + return find_impl(key, hash); + } + + + template + std::pair equal_range(const K& key) { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) { + iterator it = find(key, hash); + return std::make_pair(it, (it == end())?it:std::next(it)); + } + + + template + std::pair equal_range(const K& key) const { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) const { + const_iterator it = find(key, hash); + return std::make_pair(it, (it == cend())?it:std::next(it)); + } + + /* + * Bucket interface + */ + size_type bucket_count() const { + return m_bucket_count; + } + + size_type max_bucket_count() const { + return std::min(GrowthPolicy::max_bucket_count(), m_buckets.max_size()); + } + + /* + * Hash policy + */ + float load_factor() const { + return float(m_nb_elements)/float(bucket_count()); + } + + float max_load_factor() const { + return m_max_load_factor; + } + + void max_load_factor(float ml) { + m_max_load_factor = std::max(0.1f, std::min(ml, 0.95f)); + m_load_threshold = size_type(float(bucket_count())*m_max_load_factor); + } + + void rehash(size_type count) { + count = std::max(count, size_type(std::ceil(float(size())/max_load_factor()))); + rehash_impl(count); + } + + void reserve(size_type count) { + rehash(size_type(std::ceil(float(count)/max_load_factor()))); + } + + /* + * Observers + */ + hasher hash_function() const { + return static_cast(*this); + } + + key_equal key_eq() const { + return static_cast(*this); + } + + + /* + * Other + */ + iterator mutable_iterator(const_iterator pos) { + return iterator(m_buckets.begin() + std::distance(m_buckets.cbegin(), pos.m_iterator)); + } + +private: + template + std::size_t hash_key(const K& key) const { + return Hash::operator()(key); + } + + template + bool compare_keys(const K1& key1, const K2& key2) const { + return KeyEqual::operator()(key1, key2); + } + + std::size_t bucket_for_hash(std::size_t hash) const { + return GrowthPolicy::bucket_for_hash(hash); + } + + template::value>::type* = nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_assert(index < bucket_count()); + + return (index + 1) & this->m_mask; + } + + template::value>::type* = nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_assert(index < bucket_count()); + + index++; + return (index != bucket_count())?index:0; + } + + + + template + iterator find_impl(const K& key, std::size_t hash) { + return mutable_iterator(static_cast(this)->find(key, hash)); + } + + template + const_iterator find_impl(const K& key, std::size_t hash) const { + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + if (TSL_LIKELY((!USE_STORED_HASH_ON_LOOKUP || m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key))) + { + return const_iterator(m_buckets.begin() + ibucket); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + return cend(); + } + + void erase_from_bucket(iterator pos) { + pos.m_iterator->clear(); + m_nb_elements--; + + /** + * Backward shift, swap the empty bucket, previous_ibucket, with the values on its right, ibucket, + * until we cross another empty bucket or if the other bucket has a distance_from_ideal_bucket == 0. + * + * We try to move the values closer to their ideal bucket. + */ + std::size_t previous_ibucket = std::size_t(std::distance(m_buckets.begin(), pos.m_iterator)); + std::size_t ibucket = next_bucket(previous_ibucket); + + while(m_buckets[ibucket].dist_from_ideal_bucket() > 0) { + tsl_assert(m_buckets[previous_ibucket].empty()); + + const distance_type new_distance = distance_type(m_buckets[ibucket].dist_from_ideal_bucket() - 1); + m_buckets[previous_ibucket].set_value_of_empty_bucket(new_distance, m_buckets[ibucket].truncated_hash(), + std::move(m_buckets[ibucket].value())); + m_buckets[ibucket].clear(); + + previous_ibucket = ibucket; + ibucket = next_bucket(ibucket); + } + } + + template + std::pair insert_impl(const K& key, Args&&... value_type_args) { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + if((!USE_STORED_HASH_ON_LOOKUP || m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key)) + { + return std::make_pair(iterator(m_buckets.begin() + ibucket), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + } + + + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } + else { + insert_value(ibucket, dist_from_ideal_bucket, bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } + + + m_nb_elements++; + /* + * The value will be inserted in ibucket in any case, either because it was + * empty or by stealing the bucket (robin hood). + */ + return std::make_pair(iterator(m_buckets.begin() + ibucket), true); + } + + + template + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, Args&&... value_type_args) + { + value_type value(std::forward(value_type_args)...); + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + // fix issue #6 (see https://github.com/Tessil/robin-map/commit/965dacd191502d310f053cc00551ea8fc2f6c7f0) + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) + { + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + /* + * We don't use `value_type&& value` as last argument due to a bug in MSVC when `value_type` is a pointer, + * The compiler is not able to see the difference between `std::string*` and `std::string*&&` resulting in + * compile error. + * + * The `value` will be in a moved state at the end of the function. + */ + void insert_value_impl(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type& value) + { + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + + while(!m_buckets[ibucket].empty()) { + if(dist_from_ideal_bucket > m_buckets[ibucket].dist_from_ideal_bucket()) { + if(dist_from_ideal_bucket >= REHASH_ON_HIGH_NB_PROBES__NPROBES && + load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) + { + /** + * The number of probes is really high, rehash the map on the next insert. + * Difficult to do now as rehash may throw. + */ + m_grow_on_next_insert = true; + } + + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, hash, std::move(value)); + } + + + void rehash_impl(size_type count) { + robin_hash new_table(count, static_cast(*this), static_cast(*this), + get_allocator(), m_max_load_factor); + + const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_table.bucket_count()); + for(auto& bucket: m_buckets) { + if(bucket.empty()) { + continue; + } + + const std::size_t hash = use_stored_hash?bucket.truncated_hash(): + new_table.hash_key(KeySelect()(bucket.value())); + + new_table.insert_value_on_rehash(new_table.bucket_for_hash(hash), 0, + bucket_entry::truncate_hash(hash), std::move(bucket.value())); + } + + new_table.m_nb_elements = m_nb_elements; + new_table.swap(*this); + } + + void insert_value_on_rehash(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) + { + while(true) { + if(dist_from_ideal_bucket > m_buckets[ibucket].dist_from_ideal_bucket()) { + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, hash, std::move(value)); + return; + } + else { + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + } + } + + dist_from_ideal_bucket++; + ibucket = next_bucket(ibucket); + } + } + + + + /** + * Return true if the map has been rehashed. + */ + bool grow_on_high_load() { + if(m_grow_on_next_insert || size() >= m_load_threshold) { + rehash_impl(GrowthPolicy::next_bucket_count()); + m_grow_on_next_insert = false; + + return true; + } + + return false; + } + + +public: + static const size_type DEFAULT_INIT_BUCKETS_SIZE = 16; + static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.5f; + +private: + static const distance_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128; + static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f; + +private: + buckets_container_type m_buckets; + + /** + * Used a lot in find, avoid the call to m_buckets.size() which is a bit slower. + */ + size_type m_bucket_count; + + size_type m_nb_elements; + + size_type m_load_threshold; + float m_max_load_factor; + + bool m_grow_on_next_insert; +}; + +} + +} + +#endif diff --git a/package/android/libs/filament/include/tsl/robin_map.h b/package/android/libs/filament/include/tsl/robin_map.h new file mode 100644 index 00000000..5958e70f --- /dev/null +++ b/package/android/libs/filament/include/tsl/robin_map.h @@ -0,0 +1,668 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_MAP_H +#define TSL_ROBIN_MAP_H + + +#include +#include +#include +#include +#include +#include +#include "robin_hash.h" + + +namespace tsl { + + +/** + * Implementation of a hash map using open-adressing and the robin hood hashing algorithm with backward shift deletion. + * + * For operations modifying the hash map (insert, erase, rehash, ...), the strong exception guarantee + * is only guaranteed when the expression `std::is_nothrow_swappable>::value && + * std::is_nothrow_move_constructible>::value` is true, otherwise if an exception + * is thrown during the swap or the move, the hash map may end up in a undefined state. Per the standard + * a `Key` or `T` with a noexcept copy constructor and no move constructor also satisfies the + * `std::is_nothrow_move_constructible>::value` criterion (and will thus guarantee the + * strong exception for the map). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve + * the performance during lookups if the `KeyEqual` function takes time (if it engenders a cache-miss for example) + * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used + * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. + * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. + * `sizeof(tsl::detail_robin_hash::bucket_entry) == + * sizeof(tsl::detail_robin_hash::bucket_entry)`) and `tsl::rh::power_of_two_growth_policy` is + * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the map grows and consequently how a hash value is mapped to a bucket. + * By default the map uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets + * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo. + * Other growth policies are available and you may define your own growth policy, + * check `tsl::rh::power_of_two_growth_policy` for the interface. + * + * If the destructor of `Key` or `T` throws an exception, the behaviour of the class is undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_map { +private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const std::pair& key_value) const noexcept { + return key_value.first; + } + + key_type& operator()(std::pair& key_value) noexcept { + return key_value.first; + } + }; + + class ValueSelect { + public: + using value_type = T; + + const value_type& operator()(const std::pair& key_value) const noexcept { + return key_value.second; + } + + value_type& operator()(std::pair& key_value) noexcept { + return key_value.second; + } + }; + + using ht = detail_robin_hash::robin_hash, KeySelect, ValueSelect, + Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>; + +public: + using key_type = typename ht::key_type; + using mapped_type = T; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + +public: + /* + * Constructors + */ + robin_map(): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit robin_map(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + robin_map(size_type bucket_count, + const Allocator& alloc): robin_map(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_map(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_map(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit robin_map(const Allocator& alloc): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): robin_map(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): robin_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_map(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + robin_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + robin_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + robin_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_map& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + template::value>::type* = nullptr> + std::pair insert(P&& value) { + return m_ht.emplace(std::forward

(value)); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert(hint, value); + } + + template::value>::type* = nullptr> + iterator insert(const_iterator hint, P&& value) { + return m_ht.emplace_hint(hint, std::forward

(value)); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert(hint, std::move(value)); + } + + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + + + + template + std::pair insert_or_assign(const key_type& k, M&& obj) { + return m_ht.insert_or_assign(k, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& k, M&& obj) { + return m_ht.insert_or_assign(std::move(k), std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { + return m_ht.insert_or_assign(hint, k, std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { + return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); + } + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + + template + std::pair try_emplace(const key_type& k, Args&&... args) { + return m_ht.try_emplace(k, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& k, Args&&... args) { + return m_ht.try_emplace(std::move(k), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { + return m_ht.try_emplace(hint, k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { + return m_ht.try_emplace(hint, std::move(k), std::forward(args)...); + } + + + + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(robin_map& other) { other.m_ht.swap(m_ht); } + + + + /* + * Lookup + */ + T& at(const Key& key) { return m_ht.at(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + const T& at(const Key& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const Key& key, std::size_t precalculated_hash) + */ + const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + T& at(const K& key) { return m_ht.at(key); } + + /** + * @copydoc at(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + /** + * @copydoc at(const K& key) + */ + template::value>::type* = nullptr> + const T& at(const K& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + + + T& operator[](const Key& key) { return m_ht[key]; } + T& operator[](Key&& key) { return m_ht[std::move(key)]; } + + + + + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + friend bool operator==(const robin_map& lhs, const robin_map& rhs) { + if(lhs.size() != rhs.size()) { + return false; + } + + for(const auto& element_lhs: lhs) { + const auto it_element_rhs = rhs.find(element_lhs.first); + if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) { + return false; + } + } + + return true; + } + + friend bool operator!=(const robin_map& lhs, const robin_map& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_map& lhs, robin_map& rhs) { + lhs.swap(rhs); + } + +private: + ht m_ht; +}; + + +/** + * Same as `tsl::robin_map`. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false> +using robin_pg_map = robin_map; + +} // end namespace tsl + +#endif diff --git a/package/android/libs/filament/include/tsl/robin_set.h b/package/android/libs/filament/include/tsl/robin_set.h new file mode 100644 index 00000000..4e4667e2 --- /dev/null +++ b/package/android/libs/filament/include/tsl/robin_set.h @@ -0,0 +1,535 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_SET_H +#define TSL_ROBIN_SET_H + + +#include +#include +#include +#include +#include +#include +#include "robin_hash.h" + + +namespace tsl { + + +/** + * Implementation of a hash set using open-adressing and the robin hood hashing algorithm with backward shift deletion. + * + * For operations modifying the hash set (insert, erase, rehash, ...), the strong exception guarantee + * is only guaranteed when the expression `std::is_nothrow_swappable::value && + * std::is_nothrow_move_constructible::value` is true, otherwise if an exception + * is thrown during the swap or the move, the hash set may end up in a undefined state. Per the standard + * a `Key` with a noexcept copy constructor and no move constructor also satisfies the + * `std::is_nothrow_move_constructible::value` criterion (and will thus guarantee the + * strong exception for the set). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve + * the performance during lookups if the `KeyEqual` function takes time (or engenders a cache-miss for example) + * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used + * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. + * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. + * `sizeof(tsl::detail_robin_hash::bucket_entry) == + * sizeof(tsl::detail_robin_hash::bucket_entry)`) and `tsl::rh::power_of_two_growth_policy` is + * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the set grows and consequently how a hash value is mapped to a bucket. + * By default the set uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets + * to a power of two and uses a mask to set the hash to a bucket instead of the slow modulo. + * Other growth policies are available and you may define your own growth policy, + * check `tsl::rh::power_of_two_growth_policy` for the interface. + * + * If the destructor of `Key` throws an exception, the behaviour of the class is undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_set { +private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const Key& key) const noexcept { + return key; + } + + key_type& operator()(Key& key) noexcept { + return key; + } + }; + + using ht = detail_robin_hash::robin_hash; + +public: + using key_type = typename ht::key_type; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + + /* + * Constructors + */ + robin_set(): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit robin_set(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + robin_set(size_type bucket_count, + const Allocator& alloc): robin_set(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_set(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_set(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit robin_set(const Allocator& alloc): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): robin_set(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + robin_set& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(robin_set& other) { other.m_ht.swap(m_ht); } + + + + /* + * Lookup + */ + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); } + + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + friend bool operator==(const robin_set& lhs, const robin_set& rhs) { + if(lhs.size() != rhs.size()) { + return false; + } + + for(const auto& element_lhs: lhs) { + const auto it_element_rhs = rhs.find(element_lhs); + if(it_element_rhs == rhs.cend()) { + return false; + } + } + + return true; + } + + friend bool operator!=(const robin_set& lhs, const robin_set& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_set& lhs, robin_set& rhs) { + lhs.swap(rhs); + } + +private: + ht m_ht; +}; + + +/** + * Same as `tsl::robin_set`. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + bool StoreHash = false> +using robin_pg_set = robin_set; + +} // end namespace tsl + +#endif + diff --git a/package/android/libs/filament/include/uberz/ArchiveEnums.h b/package/android/libs/filament/include/uberz/ArchiveEnums.h new file mode 100644 index 00000000..b2741be9 --- /dev/null +++ b/package/android/libs/filament/include/uberz/ArchiveEnums.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef UBERZ_ARCHIVE_ENUMS_H +#define UBERZ_ARCHIVE_ENUMS_H + +#include + +namespace filament::uberz { + + enum class ArchiveFeature : uint64_t { + UNSUPPORTED, + OPTIONAL, + REQUIRED, + }; + +} // namespace filament::uberz + +#endif // UBERZ_ARCHIVE_ENUMS_H diff --git a/package/android/libs/filament/include/uberz/ReadableArchive.h b/package/android/libs/filament/include/uberz/ReadableArchive.h new file mode 100644 index 00000000..5d78cb26 --- /dev/null +++ b/package/android/libs/filament/include/uberz/ReadableArchive.h @@ -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. + */ + +#ifndef UBERZ_READABLE_ARCHIVE_H +#define UBERZ_READABLE_ARCHIVE_H + +#include + +#include + +#include + +namespace filament::uberz { + +// ArchiveSpec is a parse-free binary format. The client simply casts a word-aligned content blob +// into a ReadableArchive struct pointer, then calls the following function to convert all the +// offset fields into pointers. +void convertOffsetsToPointers(struct ReadableArchive* archive); + +UTILS_WARNING_PUSH +UTILS_WARNING_ENABLE_PADDED + +// Precompiled set of materials bundled with a list of features flags that each material supports. +// This is the readable counterpart to WriteableArchive. +// Used by gltfio; users do not need to access this class directly. +struct ReadableArchive { + uint32_t magic; + uint32_t version; + uint64_t specsCount; + union { + struct ArchiveSpec* specs; + uint64_t specsOffset; + }; +}; + +static constexpr Shading INVALID_SHADING_MODEL = (Shading) 0xff; +static constexpr BlendingMode INVALID_BLENDING = (BlendingMode) 0xff; + +struct ArchiveSpec { + Shading shadingModel; + BlendingMode blendingMode; + uint16_t flagsCount; + uint32_t packageByteCount; + union { + struct ArchiveFlag* flags; + uint64_t flagsOffset; + }; + union { + uint8_t* package; + uint64_t packageOffset; + }; +}; + +struct ArchiveFlag { + union { + const char* name; + uint64_t nameOffset; + }; + ArchiveFeature value; +}; + +UTILS_WARNING_POP + +} // namespace filament::uberz + +#endif // UBERZ_READABLE_ARCHIVE_H diff --git a/package/android/libs/filament/include/uberz/WritableArchive.h b/package/android/libs/filament/include/uberz/WritableArchive.h new file mode 100644 index 00000000..e511d95f --- /dev/null +++ b/package/android/libs/filament/include/uberz/WritableArchive.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef UBERZ_WRITABLE_ARCHIVE_H +#define UBERZ_WRITABLE_ARCHIVE_H + +#include + +#include +#include +#include + +#include + +#include + +namespace filament::uberz { + +// Precompiled set of materials bundled with a list of features flags that each material supports. +// This is the writeable counterpart to ReadableArchive. +// Users do not need to access this class directly, they should go through gltfio. +class WritableArchive { +public: + WritableArchive(size_t materialCount) : mMaterials(uint32_t(materialCount)) { + assert(materialCount <= UINT_MAX); + } + + void addMaterial(const char* name, const uint8_t* package, size_t packageSize); + void addSpecLine(std::string_view line); + utils::FixedCapacityVector serialize() const; + + // Low-level alternatives to addSpecLine that do not involve parsing: + void setShadingModel(Shading sm); + void setBlendingModel(BlendingMode bm); + void setFeatureFlag(const char* key, ArchiveFeature value); + +private: + size_t mLineNumber = 1; + ssize_t mMaterialIndex = -1; + + struct Material { + utils::CString name; + utils::FixedCapacityVector package; + Shading shadingModel; + BlendingMode blendingMode; + tsl::robin_map flags; + }; + + utils::FixedCapacityVector mMaterials; +}; + +} // namespace filament::uberz + +#endif // UBERZ_WRITABLE_ARCHIVE_H diff --git a/package/android/libs/filament/include/utils/Allocator.h b/package/android/libs/filament/include/utils/Allocator.h new file mode 100644 index 00000000..073206f4 --- /dev/null +++ b/package/android/libs/filament/include/utils/Allocator.h @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_ALLOCATOR_H +#define TNT_UTILS_ALLOCATOR_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace utils { + +namespace pointermath { + +template +static inline P* add(P* a, T b) noexcept { + return (P*)(uintptr_t(a) + uintptr_t(b)); +} + +template +static inline P* align(P* p, size_t alignment) noexcept { + // alignment must be a power-of-two + assert_invariant(alignment && !(alignment & alignment-1)); + return (P*)((uintptr_t(p) + alignment - 1) & ~(alignment - 1)); +} + +template +static inline P* align(P* p, size_t alignment, size_t offset) noexcept { + P* const r = align(add(p, offset), alignment); + assert_invariant(r >= add(p, offset)); + return r; +} + +} + +/* ------------------------------------------------------------------------------------------------ + * LinearAllocator + * + * + Allocates blocks linearly + * + Cannot free individual blocks + * + Can free top of memory back up to a specified point + * + Doesn't call destructors + * ------------------------------------------------------------------------------------------------ + */ + +class LinearAllocator { +public: + // use memory area provided + LinearAllocator(void* begin, void* end) noexcept; + + template + explicit LinearAllocator(const AREA& area) : LinearAllocator(area.begin(), area.end()) { } + + // Allocators can't be copied + LinearAllocator(const LinearAllocator& rhs) = delete; + LinearAllocator& operator=(const LinearAllocator& rhs) = delete; + + // Allocators can be moved + LinearAllocator(LinearAllocator&& rhs) noexcept; + LinearAllocator& operator=(LinearAllocator&& rhs) noexcept; + + ~LinearAllocator() noexcept = default; + + // our allocator concept + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t), size_t extra = 0) UTILS_RESTRICT { + // branch-less allocation + void* const p = pointermath::align(current(), alignment, extra); + void* const c = pointermath::add(p, size); + bool const success = c <= end(); + set_current(success ? c : current()); + return success ? p : nullptr; + } + + // API specific to this allocator + void *getCurrent() UTILS_RESTRICT noexcept { + return current(); + } + + // free memory back to the specified point + void rewind(void* p) UTILS_RESTRICT noexcept { + assert_invariant(p >= mBegin && p < end()); + set_current(p); + } + + // frees all allocated blocks + void reset() UTILS_RESTRICT noexcept { + rewind(mBegin); + } + + size_t allocated() const UTILS_RESTRICT noexcept { + return mSize; + } + + size_t available() const UTILS_RESTRICT noexcept { + return mSize - mCur; + } + + void swap(LinearAllocator& rhs) noexcept; + + void *base() noexcept { return mBegin; } + void const *base() const noexcept { return mBegin; } + + void free(void*, size_t) UTILS_RESTRICT noexcept { } + +protected: + void* end() UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mSize); } + void const* end() const UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mSize); } + + void* current() UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mCur); } + void const* current() const UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mCur); } + +private: + void set_current(void* p) UTILS_RESTRICT noexcept { + mCur = uint32_t(uintptr_t(p) - uintptr_t(mBegin)); + } + void* mBegin = nullptr; + uint32_t mSize = 0; + uint32_t mCur = 0; +}; + +/* ------------------------------------------------------------------------------------------------ + * HeapAllocator + * + * + uses malloc() for all allocations + * + frees blocks with free() + * ------------------------------------------------------------------------------------------------ + */ +class HeapAllocator { +public: + HeapAllocator() noexcept = default; + + template + explicit HeapAllocator(const AREA&) { } + + // our allocator concept + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)) { + return aligned_alloc(size, alignment); + } + + void free(void* p) noexcept { + aligned_free(p); + } + + void free(void* p, size_t) noexcept { + this->free(p); + } + + ~HeapAllocator() noexcept = default; + + void swap(HeapAllocator&) noexcept { } +}; + +/* ------------------------------------------------------------------------------------------------ + * LinearAllocatorWithFallback + * + * This is a LinearAllocator that falls back to a HeapAllocator when allocation fail. The Heap + * allocator memory is freed only when the LinearAllocator is reset or destroyed. + * ------------------------------------------------------------------------------------------------ + */ +class LinearAllocatorWithFallback : private LinearAllocator, private HeapAllocator { + std::vector mHeapAllocations; +public: + LinearAllocatorWithFallback(void* begin, void* end) noexcept + : LinearAllocator(begin, end) { + } + + template + explicit LinearAllocatorWithFallback(const AREA& area) + : LinearAllocatorWithFallback(area.begin(), area.end()) { + } + + ~LinearAllocatorWithFallback() noexcept { + LinearAllocatorWithFallback::reset(); + } + + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)); + + void *getCurrent() noexcept { + return LinearAllocator::getCurrent(); + } + + void rewind(void* p) noexcept { + if (p >= LinearAllocator::base() && p < LinearAllocator::end()) { + LinearAllocator::rewind(p); + } + } + + void reset() noexcept; + + void free(void*, size_t) noexcept { } + + bool isHeapAllocation(void* p) const noexcept { + return p < LinearAllocator::base() || p >= LinearAllocator::end(); + } +}; + +// ------------------------------------------------------------------------------------------------ + +class FreeList { +public: + FreeList() noexcept = default; + FreeList(void* begin, void* end, size_t elementSize, size_t alignment, size_t extra) noexcept; + FreeList(const FreeList& rhs) = delete; + FreeList& operator=(const FreeList& rhs) = delete; + FreeList(FreeList&& rhs) noexcept = default; + FreeList& operator=(FreeList&& rhs) noexcept = default; + + void* pop() noexcept { + Node* const head = mHead; + mHead = head ? head->next : nullptr; + // this could indicate a use after free + assert_invariant(!mHead || mHead >= mBegin && mHead < mEnd); + return head; + } + + void push(void* p) noexcept { + assert_invariant(p); + assert_invariant(p >= mBegin && p < mEnd); + // TODO: assert this is one of our pointer (i.e.: it's address match one of ours) + Node* const head = static_cast(p); + head->next = mHead; + mHead = head; + } + + void *getFirst() noexcept { + return mHead; + } + + struct Node { + Node* next; + }; + +private: + static Node* init(void* begin, void* end, + size_t elementSize, size_t alignment, size_t extra) noexcept; + + Node* mHead = nullptr; + +#ifndef NDEBUG + // These are needed only for debugging... + void* mBegin = nullptr; + void* mEnd = nullptr; +#endif +}; + +class AtomicFreeList { +public: + AtomicFreeList() noexcept = default; + AtomicFreeList(void* begin, void* end, + size_t elementSize, size_t alignment, size_t extra) noexcept; + AtomicFreeList(const AtomicFreeList& rhs) = delete; + AtomicFreeList& operator=(const AtomicFreeList& rhs) = delete; + + void* pop() noexcept { + Node* const pStorage = mStorage; + + HeadPtr currentHead = mHead.load(); + while (currentHead.offset >= 0) { + // The value of "pNext" we load here might already contain application data if another + // thread raced ahead of us. But in that case, the computed "newHead" will be discarded + // since compare_exchange_weak fails. Then this thread will loop with the updated + // value of currentHead, and try again. + Node* const pNext = pStorage[currentHead.offset].next.load(std::memory_order_relaxed); + const HeadPtr newHead{ pNext ? int32_t(pNext - pStorage) : -1, currentHead.tag + 1 }; + // In the rare case that the other thread that raced ahead of us already returned the + // same mHead we just loaded, but it now has a different "next" value, the tag field will not + // match, and compare_exchange_weak will fail and prevent that particular race condition. + if (mHead.compare_exchange_weak(currentHead, newHead)) { + // This assert needs to occur after we have validated that there was no race condition + // Otherwise, next might already contain application data, if another thread + // raced ahead of us after we loaded mHead, but before we loaded mHead->next. + assert_invariant(!pNext || pNext >= pStorage); + break; + } + } + void* p = (currentHead.offset >= 0) ? (pStorage + currentHead.offset) : nullptr; + assert_invariant(!p || p >= pStorage); + return p; + } + + void push(void* p) noexcept { + Node* const storage = mStorage; + assert_invariant(p && p >= storage); + Node* const node = static_cast(p); + HeadPtr currentHead = mHead.load(); + HeadPtr newHead = { int32_t(node - storage), currentHead.tag + 1 }; + do { + newHead.tag = currentHead.tag + 1; + Node* const n = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr; + node->next.store(n, std::memory_order_relaxed); + } while(!mHead.compare_exchange_weak(currentHead, newHead)); + } + + void* getFirst() noexcept { + return mStorage + mHead.load(std::memory_order_relaxed).offset; + } + + struct Node { + // This should be a regular (non-atomic) pointer, but this causes TSAN to complain + // about a data-race that exists but is benin. We always use this atomic<> in + // relaxed mode. + // The data race TSAN complains about is when a pop() is interrupted by a + // pop() + push() just after mHead->next is read -- it appears as though it is written + // without synchronization (by the push), however in that case, the pop's CAS will fail + // and things will auto-correct. + // + // Pop() | + // | | + // read head->next | + // | pop() + // | | + // | read head->next + // | CAS, tag++ + // | | + // | push() + // | | + // [TSAN: data-race here] write head->next + // | CAS, tag++ + // CAS fails + // | + // read head->next + // | + // CAS, tag++ + // + std::atomic next; + }; + +private: + // This struct is using a 32-bit offset into the arena rather than + // a direct pointer, because together with the 32-bit tag, it needs to + // fit into 8 bytes. If it was any larger, it would not be possible to + // access it atomically. + struct alignas(8) HeadPtr { + int32_t offset; + uint32_t tag; + }; + + std::atomic mHead{}; + + Node* mStorage = nullptr; +}; + +// ------------------------------------------------------------------------------------------------ + +template < + size_t ELEMENT_SIZE, + size_t ALIGNMENT = alignof(std::max_align_t), + size_t OFFSET = 0, + typename FREELIST = FreeList> +class PoolAllocator { + static_assert(ELEMENT_SIZE >= sizeof(typename FREELIST::Node), + "ELEMENT_SIZE must accommodate at least a FreeList::Node"); +public: + // our allocator concept + void* alloc(size_t size = ELEMENT_SIZE, + size_t alignment = ALIGNMENT, size_t offset = OFFSET) noexcept { + assert_invariant(size <= ELEMENT_SIZE); + assert_invariant(alignment <= ALIGNMENT); + assert_invariant(offset == OFFSET); + return mFreeList.pop(); + } + + void free(void* p, size_t = ELEMENT_SIZE) noexcept { + mFreeList.push(p); + } + + constexpr size_t getSize() const noexcept { return ELEMENT_SIZE; } + + PoolAllocator(void* begin, void* end) noexcept + : mFreeList(begin, end, ELEMENT_SIZE, ALIGNMENT, OFFSET) { + } + + PoolAllocator(void* begin, size_t size) noexcept + : mFreeList(begin, static_cast(begin) + size, ELEMENT_SIZE, ALIGNMENT, OFFSET) { + } + + template + explicit PoolAllocator(const AREA& area) noexcept + : PoolAllocator(area.begin(), area.end()) { + } + + // Allocators can't be copied + PoolAllocator(const PoolAllocator& rhs) = delete; + PoolAllocator& operator=(const PoolAllocator& rhs) = delete; + + // Allocators can be moved + PoolAllocator(PoolAllocator&& rhs) = default; + PoolAllocator& operator=(PoolAllocator&& rhs) = default; + + PoolAllocator() noexcept = default; + ~PoolAllocator() noexcept = default; + + // API specific to this allocator + + void *getCurrent() noexcept { + return mFreeList.getFirst(); + } + +private: + FREELIST mFreeList; +}; + +#define UTILS_MAX(a,b) ((a) > (b) ? (a) : (b)) + +template +using ObjectPoolAllocator = PoolAllocator; + +template +using ThreadSafeObjectPoolAllocator = PoolAllocator; + + +// ------------------------------------------------------------------------------------------------ +// Areas +// ------------------------------------------------------------------------------------------------ + +namespace AreaPolicy { + +class StaticArea { +public: + StaticArea() noexcept = default; + + StaticArea(void* b, void* e) noexcept + : mBegin(b), mEnd(e) { + } + + ~StaticArea() noexcept = default; + + StaticArea(const StaticArea& rhs) = default; + StaticArea& operator=(const StaticArea& rhs) = default; + StaticArea(StaticArea&& rhs) noexcept = default; + StaticArea& operator=(StaticArea&& rhs) noexcept = default; + + void* data() const noexcept { return mBegin; } + void* begin() const noexcept { return mBegin; } + void* end() const noexcept { return mEnd; } + size_t size() const noexcept { return uintptr_t(mEnd) - uintptr_t(mBegin); } + + friend void swap(StaticArea& lhs, StaticArea& rhs) noexcept { + using std::swap; + swap(lhs.mBegin, rhs.mBegin); + swap(lhs.mEnd, rhs.mEnd); + } + +private: + void* mBegin = nullptr; + void* mEnd = nullptr; +}; + +class HeapArea { +public: + HeapArea() noexcept = default; + + explicit HeapArea(size_t size) { + if (size) { + // TODO: policy committing memory + mBegin = malloc(size); + mEnd = pointermath::add(mBegin, size); + } + } + + ~HeapArea() noexcept { + // TODO: policy for returning memory to system + free(mBegin); + } + + HeapArea(const HeapArea& rhs) = delete; + HeapArea& operator=(const HeapArea& rhs) = delete; + HeapArea(HeapArea&& rhs) noexcept = delete; + HeapArea& operator=(HeapArea&& rhs) noexcept = delete; + + void* data() const noexcept { return mBegin; } + void* begin() const noexcept { return mBegin; } + void* end() const noexcept { return mEnd; } + size_t size() const noexcept { return uintptr_t(mEnd) - uintptr_t(mBegin); } + + friend void swap(HeapArea& lhs, HeapArea& rhs) noexcept { + using std::swap; + swap(lhs.mBegin, rhs.mBegin); + swap(lhs.mEnd, rhs.mEnd); + } + +private: + void* mBegin = nullptr; + void* mEnd = nullptr; +}; + +class NullArea { +public: + void* data() const noexcept { return nullptr; } + size_t size() const noexcept { return 0; } +}; + +} // namespace AreaPolicy + +// ------------------------------------------------------------------------------------------------ +// Policies +// ------------------------------------------------------------------------------------------------ + +namespace LockingPolicy { + +struct NoLock { + void lock() noexcept { } + void unlock() noexcept { } +}; + +using Mutex = utils::Mutex; + +} // namespace LockingPolicy + + +namespace TrackingPolicy { + +// default no-op tracker +struct Untracked { + Untracked() noexcept = default; + Untracked(const char* name, void* base, size_t size) noexcept { + (void)name, void(base), (void)size; + } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept { + (void)p, (void)size, (void)alignment, (void)extra; + } + void onFree(void* p, size_t = 0) noexcept { (void)p; } + void onReset() noexcept { } + void onRewind(void* addr) noexcept { (void)addr; } +}; + +// This just track the max memory usage and logs it in the destructor +struct HighWatermark { + HighWatermark() noexcept = default; + HighWatermark(const char* name, void* base, size_t size) noexcept + : mName(name), mBase(base), mSize(uint32_t(size)) { } + ~HighWatermark() noexcept; + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept; + void onFree(void* p, size_t size) noexcept; + void onReset() noexcept; + void onRewind(void const* addr) noexcept; + uint32_t getHighWatermark() const noexcept { return mHighWaterMark; } +protected: + const char* mName = nullptr; + void* mBase = nullptr; + uint32_t mSize = 0; + uint32_t mCurrent = 0; + uint32_t mHighWaterMark = 0; +}; + +// This just fills buffers with known values to help catch uninitialized access and use after free. +struct Debug { + Debug() noexcept = default; + Debug(const char* name, void* base, size_t size) noexcept + : mName(name), mBase(base), mSize(uint32_t(size)) { } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept; + void onFree(void* p, size_t size) noexcept; + void onReset() noexcept; + void onRewind(void* addr) noexcept; +protected: + const char* mName = nullptr; + void* mBase = nullptr; + uint32_t mSize = 0; +}; + +struct DebugAndHighWatermark : protected HighWatermark, protected Debug { + DebugAndHighWatermark() noexcept = default; + DebugAndHighWatermark(const char* name, void* base, size_t size) noexcept + : HighWatermark(name, base, size), Debug(name, base, size) { } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept { + HighWatermark::onAlloc(p, size, alignment, extra); + Debug::onAlloc(p, size, alignment, extra); + } + void onFree(void* p, size_t size) noexcept { + HighWatermark::onFree(p, size); + Debug::onFree(p, size); + } + void onReset() noexcept { + HighWatermark::onReset(); + Debug::onReset(); + } + void onRewind(void* addr) noexcept { + HighWatermark::onRewind(addr); + Debug::onRewind(addr); + } +}; + +} // namespace TrackingPolicy + +// ------------------------------------------------------------------------------------------------ +// Arenas +// ------------------------------------------------------------------------------------------------ + +template +class Arena { +public: + + Arena() = default; + + // construct an arena with a name and forward argument to its allocator + template + Arena(const char* name, size_t size, ARGS&& ... args) + : mArenaName(name), + mArea(size), + mAllocator(mArea, std::forward(args) ... ), + mListener(name, mArea.data(), mArea.size()) { + } + + template + Arena(const char* name, AreaPolicy&& area, ARGS&& ... args) + : mArenaName(name), + mArea(std::forward(area)), + mAllocator(mArea, std::forward(args) ... ), + mListener(name, mArea.data(), mArea.size()) { + } + + template + void* alloc(size_t size, size_t alignment, size_t extra, ARGS&& ... args) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment, extra, std::forward(args) ...); + mListener.onAlloc(p, size, alignment, extra); + return p; + } + + + // allocate memory from arena with given size and alignment + // (acceptable size/alignment may depend on the allocator provided) + void* alloc(size_t size, size_t alignment, size_t extra) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment, extra); + mListener.onAlloc(p, size, alignment, extra); + return p; + } + + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment); + mListener.onAlloc(p, size, alignment, 0); + return p; + } + + // Allocate an array of trivially destructible objects + // for safety, we disable the object-based alloc method if the object type is not + // trivially destructible, since free() won't call the destructor and this is allocating + // an array. + template ::value>::type> + T* alloc(size_t count, size_t alignment, size_t extra) noexcept { + return (T*)alloc(count * sizeof(T), alignment, extra); + } + + template ::value>::type> + T* alloc(size_t count, size_t alignment = alignof(T)) noexcept { + return (T*)alloc(count * sizeof(T), alignment); + } + + // some allocators require more parameters + template + void free(void* p, size_t size, ARGS&& ... args) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p, size); + mAllocator.free(p, size, std::forward(args) ...); + } + } + + // some allocators require the size of the allocation for free + void free(void* p, size_t size) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p, size); + mAllocator.free(p, size); + } + } + + // return memory pointed by p to the arena + // (actual behaviour may depend on allocator provided) + void free(void* p) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p); + mAllocator.free(p); + } + } + + // some allocators don't have a free() call, but a single reset() or rewind() instead + void reset() noexcept { + std::lock_guard guard(mLock); + mListener.onReset(); + mAllocator.reset(); + } + + void* getCurrent() noexcept { return mAllocator.getCurrent(); } + + void rewind(void *addr) noexcept { + std::lock_guard guard(mLock); + mListener.onRewind(addr); + mAllocator.rewind(addr); + } + + // Allocate and construct an object + template + T* make(ARGS&& ... args) noexcept { + void* const p = this->alloc(sizeof(T), ALIGN); + return p ? new(p) T(std::forward(args)...) : nullptr; + } + + // destroys an object created with make() above, and frees associated memory + template + void destroy(T* p) noexcept { + if (p) { + p->~T(); + this->free((void*)p, sizeof(T)); + } + } + + char const* getName() const noexcept { return mArenaName; } + + AllocatorPolicy& getAllocator() noexcept { return mAllocator; } + AllocatorPolicy const& getAllocator() const noexcept { return mAllocator; } + + TrackingPolicy& getListener() noexcept { return mListener; } + TrackingPolicy const& getListener() const noexcept { return mListener; } + + AreaPolicy& getArea() noexcept { return mArea; } + AreaPolicy const& getArea() const noexcept { return mArea; } + + void setListener(TrackingPolicy listener) noexcept { + std::swap(mListener, listener); + } + + template + void emplaceListener(ARGS&& ... args) noexcept { + mListener.~TrackingPolicy(); + new (&mListener) TrackingPolicy(std::forward(args)...); + } + + // An arena can't be copied + Arena(Arena const& rhs) noexcept = delete; + Arena& operator=(Arena const& rhs) noexcept = delete; + + friend void swap(Arena& lhs, Arena& rhs) noexcept { + using std::swap; + swap(lhs.mArea, rhs.mArea); + swap(lhs.mAllocator, rhs.mAllocator); + swap(lhs.mLock, rhs.mLock); + swap(lhs.mListener, rhs.mListener); + swap(lhs.mArenaName, rhs.mArenaName); + } + +private: + char const* mArenaName = nullptr; + AreaPolicy mArea; + // note: we should use something like compressed_pair for the members below + AllocatorPolicy mAllocator; + LockingPolicy mLock; + TrackingPolicy mListener; +}; + +// ------------------------------------------------------------------------------------------------ + +template +using HeapArena = Arena; + +// ------------------------------------------------------------------------------------------------ + +// This doesn't implement our allocator concept, because it's too risky to use this as an allocator +// in particular, doing ArenaScope. +template +class ArenaScope { + + struct Finalizer { + void (*finalizer)(void* p) = nullptr; + Finalizer* next = nullptr; + }; + + template + static void destruct(void* p) noexcept { + static_cast(p)->~T(); + } + +public: + using Arena = ARENA; + + explicit ArenaScope(ARENA& allocator) + : mArena(allocator), mRewind(allocator.getCurrent()) { + } + + ArenaScope& operator=(const ArenaScope& rhs) = delete; + ArenaScope(ArenaScope&& rhs) noexcept = delete; + ArenaScope& operator=(ArenaScope&& rhs) noexcept = delete; + + ~ArenaScope() { + // run the finalizer chain + Finalizer* head = mFinalizerHead; + while (head) { + void* p = pointermath::add(head, sizeof(Finalizer)); + head->finalizer(p); + head = head->next; + } + // ArenaScope works only with Arena that implements rewind() + mArena.rewind(mRewind); + } + + template + T* make(ARGS&& ... args) noexcept { + T* o = nullptr; + if (std::is_trivially_destructible::value) { + o = mArena.template make(std::forward(args)...); + } else { + void* const p = (Finalizer*)mArena.alloc(sizeof(T), ALIGN, sizeof(Finalizer)); + if (p != nullptr) { + Finalizer* const f = static_cast(p) - 1; + // constructor must be called before adding the dtor to the list + // so that the ctor can allocate objects in a nested scope and have the + // finalizers called in reverse order. + o = new(p) T(std::forward(args)...); + f->finalizer = &destruct; + f->next = mFinalizerHead; + mFinalizerHead = f; + } + } + return o; + } + + void* allocate(size_t size, size_t alignment = 1) noexcept { + return mArena.template alloc(size, alignment, 0); + } + + template + T* allocate(size_t size, size_t alignment = alignof(T), size_t extra = 0) noexcept { + return mArena.template alloc(size, alignment, extra); + } + + // use with caution + ARENA& getArena() noexcept { return mArena; } + +private: + ARENA& mArena; + void* mRewind = nullptr; + Finalizer* mFinalizerHead = nullptr; +}; + + +template +class STLAllocator { +public: + using value_type = TYPE; + using pointer = TYPE*; + using const_pointer = const TYPE*; + using reference = TYPE&; + using const_reference = const TYPE&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + template + struct rebind { using other = STLAllocator; }; + +public: + // we don't make this explicit, so that we can initialize a vector using a STLAllocator + // from an Arena, avoiding to have to repeat the vector type. + STLAllocator(ARENA& arena) : mArena(arena) { } // NOLINT(google-explicit-constructor) + + template + explicit STLAllocator(STLAllocator const& rhs) : mArena(rhs.mArena) { } + + TYPE* allocate(std::size_t n) { + auto p = static_cast(mArena.alloc(n * sizeof(TYPE), alignof(TYPE))); + assert_invariant(p); + return p; + } + + void deallocate(TYPE* p, std::size_t n) { + mArena.free(p, n * sizeof(TYPE)); + } + + // these should be out-of-class friends, but this doesn't seem to work with some compilers + // which complain about multiple definition each time a STLAllocator<> is instantiated. + template + bool operator==(const STLAllocator& rhs) const noexcept { + return std::addressof(mArena) == std::addressof(rhs.mArena); + } + + template + bool operator!=(const STLAllocator& rhs) const noexcept { + return !operator==(rhs); + } + +private: + template + friend class STLAllocator; + + ARENA& mArena; +}; + +} // namespace utils + +#endif // TNT_UTILS_ALLOCATOR_H diff --git a/package/android/libs/filament/include/utils/BitmaskEnum.h b/package/android/libs/filament/include/utils/BitmaskEnum.h new file mode 100644 index 00000000..17f94d21 --- /dev/null +++ b/package/android/libs/filament/include/utils/BitmaskEnum.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_UTILS_BITMASKENUM_H +#define TNT_UTILS_BITMASKENUM_H + +#include // for std::false_type + +#include +#include + +namespace utils { + +template +struct EnableBitMaskOperators : public std::false_type { }; + +template +struct EnableIntegerOperators : public std::false_type { }; + +namespace Enum { + +template +size_t count(); + +} // namespace enum +} // namespace utils + +// ------------------------------------------------------------------------------------------------ + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr int operator+(Enum value) noexcept { + return int(value); +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator==(Enum lhs, size_t rhs) noexcept { + using underlying_t = std::underlying_type_t; + return underlying_t(lhs) == rhs; +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator==(size_t lhs, Enum rhs) noexcept { + return rhs == lhs; +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator!=(Enum lhs, size_t rhs) noexcept { + return !(rhs == lhs); +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator!=(size_t lhs, Enum rhs) noexcept { + return rhs != lhs; +} + +// ------------------------------------------------------------------------------------------------ + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool operator!(Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return underlying(rhs) == 0; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator~(Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(~underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator|(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) | underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator&(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) & underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator^(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) ^ underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator|=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs | rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator&=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs & rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator^=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs ^ rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool none(Enum lhs) noexcept { + return !lhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool any(Enum lhs) noexcept { + return !none(lhs); +} + +#endif // TNT_UTILS_BITMASKENUM_H diff --git a/package/android/libs/filament/include/utils/CString.h b/package/android/libs/filament/include/utils/CString.h new file mode 100644 index 00000000..d5b76951 --- /dev/null +++ b/package/android/libs/filament/include/utils/CString.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_CSTRING_H +#define TNT_UTILS_CSTRING_H + +// NOTE: this header should not include STL headers + +#include + +#include +#include +#include +#include +#include + +namespace utils { + +//! \privatesection +struct hashCStrings { + typedef const char* argument_type; + typedef size_t result_type; + result_type operator()(argument_type cstr) const noexcept { + size_t hash = 5381; + while (int const c = *cstr++) { + hash = (hash * 33u) ^ size_t(c); + } + return hash; + } +}; + +template +using StringLiteral = const char[N]; + + +// ------------------------------------------------------------------------------------------------ + +class UTILS_PUBLIC CString { +public: + using value_type = char; + using size_type = uint32_t; + using difference_type = int32_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = value_type*; + using const_iterator = const value_type*; + + CString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug + + // Allocates memory and appends a null. This constructor can be used to hold arbitrary data + // inside the string (i.e. it can contain nulls or non-ASCII encodings). + CString(const char* cstr, size_t length); + + // Allocates memory for a string of size length plus space for the null terminating character. + // Also initializes the memory to 0. This constructor can be used to hold arbitrary data + // inside the string. + explicit CString(size_t length); + + // Allocates memory and copies traditional C string content. Unlike the above constructor, this + // does not allow embedded nulls. This is explicit because this operation is costly. + explicit CString(const char* cstr); + + template + CString(StringLiteral const& other) noexcept // NOLINT(google-explicit-constructor) + : CString(other, N - 1) { + } + + CString(const CString& rhs); + + CString(CString&& rhs) noexcept { + this->swap(rhs); + } + + + CString& operator=(const CString& rhs); + + CString& operator=(CString&& rhs) noexcept { + this->swap(rhs); + return *this; + } + + ~CString() noexcept { + if (mData) { + free(mData - 1); + } + } + + void swap(CString& other) noexcept { + // don't use std::swap(), we don't want an STL dependency in this file + auto *temp = mCStr; + mCStr = other.mCStr; + other.mCStr = temp; + } + + const_pointer c_str() const noexcept { return mCStr; } + pointer c_str() noexcept { return mCStr; } + const_pointer c_str_safe() const noexcept { return mData ? c_str() : ""; } + const_pointer data() const noexcept { return c_str(); } + pointer data() noexcept { return c_str(); } + size_type size() const noexcept { return mData ? mData[-1].length : 0; } + size_type length() const noexcept { return size(); } + bool empty() const noexcept { return size() == 0; } + + iterator begin() noexcept { return mCStr; } + iterator end() noexcept { return begin() + length(); } + const_iterator begin() const noexcept { return data(); } + const_iterator end() const noexcept { return begin() + length(); } + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + + CString& replace(size_type pos, size_type len, const CString& str) noexcept; + CString& insert(size_type pos, const CString& str) noexcept { return replace(pos, 0, str); } + + const_reference operator[](size_type pos) const noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference operator[](size_type pos) noexcept { + assert(pos < size()); + return begin()[pos]; + } + + const_reference at(size_type pos) const noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference at(size_type pos) noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference front() noexcept { + assert(size()); + return begin()[0]; + } + + const_reference front() const noexcept { + assert(size()); + return begin()[0]; + } + + reference back() noexcept { + assert(size()); + return begin()[size() - 1]; + } + + const_reference back() const noexcept { + assert(size()); + return begin()[size() - 1]; + } + + // placement new declared as "throw" to avoid the compiler's null-check + inline void* operator new(size_t, void* ptr) { + assert(ptr); + return ptr; + } + + struct Hasher : private hashCStrings { + typedef CString argument_type; + typedef size_t result_type; + result_type operator()(const argument_type& s) const noexcept { + return hashCStrings::operator()(s.c_str()); + } + }; + +private: + struct Data { + size_type length; + }; + + // mCStr points to the C-string or nullptr. if non-null, mCStr is preceded by the string's size + union { + value_type *mCStr = nullptr; + Data* mData; // Data is stored at mData[-1] + }; + + int compare(const CString& rhs) const noexcept { + size_type const lhs_size = size(); + size_type const rhs_size = rhs.size(); + if (lhs_size < rhs_size) return -1; + if (lhs_size > rhs_size) return 1; + return strncmp(data(), rhs.data(), size()); + } + + friend bool operator==(CString const& lhs, CString const& rhs) noexcept { + return (lhs.data() == rhs.data()) || + ((lhs.size() == rhs.size()) && !strncmp(lhs.data(), rhs.data(), lhs.size())); + } + friend bool operator!=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs == rhs); + } + friend bool operator<(CString const& lhs, CString const& rhs) noexcept { + return lhs.compare(rhs) < 0; + } + friend bool operator>(CString const& lhs, CString const& rhs) noexcept { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs < rhs); + } + friend bool operator<=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs > rhs); + } +}; + +// implement this for your type for automatic conversion to CString. Failing to do so leads +// to a compile-time failure. +template +CString to_string(T value) noexcept; + +// ------------------------------------------------------------------------------------------------ + +template +class UTILS_PUBLIC FixedSizeString { +public: + using value_type = char; + using pointer = value_type*; + using const_pointer = const value_type*; + static_assert(N > 0); + + FixedSizeString() noexcept = default; + explicit FixedSizeString(const char* str) noexcept { + strncpy(mData, str, N - 1); // leave room for the null terminator + } + + const_pointer c_str() const noexcept { return mData; } + pointer c_str() noexcept { return mData; } + +private: + value_type mData[N] = {0}; +}; + +} // namespace utils + +#endif // TNT_UTILS_CSTRING_H diff --git a/package/android/libs/filament/include/utils/CallStack.h b/package/android/libs/filament/include/utils/CallStack.h new file mode 100644 index 00000000..33ac0b50 --- /dev/null +++ b/package/android/libs/filament/include/utils/CallStack.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef UTILS_CALLSTACK_H +#define UTILS_CALLSTACK_H + +#include +#include +#include + +#include +#include +#include + +namespace utils { + +/** + * CallStack captures the current's thread call stack. + */ +class CallStack { +public: + /** + * Creates an empty call stack + * @see CallStack::capture() + */ + CallStack() = default; + CallStack(const CallStack&) = default; + ~CallStack() = default; + + /** + * A convenience method to create and capture the stack trace in one go. + * @param ignore number frames to ignore at the top of the stack. + * @return A CallStack object + */ + static CallStack unwind(size_t ignore = 0) noexcept; + + /** + * Capture the current thread's stack and replaces the existing one if any. + * @param ignore number frames to ignore at the top of the stack. + */ + void update(size_t ignore = 0) noexcept; + + /** + * Get the number of stack frames this object has recorded. + * @return How many stack frames are accessible through operator[] + */ + size_t getFrameCount() const noexcept; + + /** + * Return the program-counter of each stack frame captured + * @param index of the frame between 0 and getFrameCount()-1 + * @return the program-counter of the stack-frame recorded at index \p index + * @throw std::out_of_range if the index is out of range + */ + intptr_t operator [](size_t index) const; + + /** Demangles a C++ type name */ + static utils::CString demangleTypeName(const char* mangled); + + template + static utils::CString typeName() { +#if UTILS_HAS_RTTI + return demangleTypeName(typeid(T).name()); +#else + return CString(""); +#endif + } + + /** + * Outputs a CallStack into a stream. + * This will print, when possible, the demangled names of functions corresponding to the + * program-counter recorded. + */ + friend utils::io::ostream& operator <<(utils::io::ostream& stream, const CallStack& callstack); + + bool operator <(const CallStack& rhs) const; + + inline bool operator >(const CallStack& rhs) const { + return rhs < *this; + } + + inline bool operator !=(const CallStack& rhs) const { + return *this < rhs || rhs < *this; + } + + inline bool operator >=(const CallStack& rhs) const { + return !operator <(rhs); + } + + inline bool operator <=(const CallStack& rhs) const { + return !operator >(rhs); + } + + inline bool operator ==(const CallStack& rhs) const { + return !operator !=(rhs); + } + +private: + void update_gcc(size_t ignore) noexcept; + + static utils::CString demangle(const char* mangled); + + static constexpr size_t NUM_FRAMES = 20; + + struct StackFrameInfo { + intptr_t pc; + }; + + size_t m_frame_count = 0; + StackFrameInfo m_stack[NUM_FRAMES]; +}; + +} // namespace utils + +#endif // UTILS_CALLSTACK_H diff --git a/package/android/libs/filament/include/utils/Entity.h b/package/android/libs/filament/include/utils/Entity.h new file mode 100644 index 00000000..58fdf606 --- /dev/null +++ b/package/android/libs/filament/include/utils/Entity.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITY_H +#define TNT_UTILS_ENTITY_H + +#include + +#include +#include + +namespace utils { + +class UTILS_PUBLIC Entity { +public: + // this can be used to create an array of to-be-filled entities (see create()) + Entity() noexcept { } // NOLINT(modernize-use-equals-default), Ubuntu compiler bug + + // Entities can be copied + Entity(const Entity& e) noexcept = default; + Entity(Entity&& e) noexcept = default; + Entity& operator=(const Entity& e) noexcept = default; + Entity& operator=(Entity&& e) noexcept = default; + + // Entities can be compared + bool operator==(Entity e) const { return e.mIdentity == mIdentity; } + bool operator!=(Entity e) const { return e.mIdentity != mIdentity; } + + // Entities can be sorted + bool operator<(Entity e) const { return e.mIdentity < mIdentity; } + + bool isNull() const noexcept { + return mIdentity == 0; + } + + // an id that can be used for debugging/printing + uint32_t getId() const noexcept { + return mIdentity; + } + + explicit operator bool() const noexcept { return !isNull(); } + + void clear() noexcept { mIdentity = 0; } + + // Exports an entity to an int32_t which can be used "as is" in the Java programing language. + static int32_t smuggle(Entity entity) noexcept { + return int32_t(entity.getId()); + } + + // Imports an entity from an int32_t generated by smuggle() above. + static Entity import(int32_t identity) noexcept { + return Entity{ Type(identity) }; + } + + struct Hasher { + typedef Entity argument_type; + typedef size_t result_type; + result_type operator()(argument_type const& e) const { + return e.getId(); + } + }; + +private: + friend class EntityManager; + friend class EntityManagerImpl; + using Type = uint32_t; + + explicit Entity(Type identity) noexcept : mIdentity(identity) { } + + Type mIdentity = 0; +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITY_H diff --git a/package/android/libs/filament/include/utils/EntityInstance.h b/package/android/libs/filament/include/utils/EntityInstance.h new file mode 100644 index 00000000..75419493 --- /dev/null +++ b/package/android/libs/filament/include/utils/EntityInstance.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITYINSTANCE_H +#define TNT_UTILS_ENTITYINSTANCE_H + +#include + +#include + +#include + +namespace utils { + +class UTILS_PUBLIC EntityInstanceBase { +public: + using Type = uint32_t; +protected: + Type mInstance = 0; +}; + +template +class UTILS_PUBLIC EntityInstance : public EntityInstanceBase { +public: + // default Instance is invalid + constexpr EntityInstance() noexcept = default; + + // check if this Instance is valid + constexpr bool isValid() const noexcept { return mInstance != 0; } + + // Instances of same type can be copied/assigned + constexpr EntityInstance(EntityInstance const& other) noexcept = default; + constexpr EntityInstance& operator=(EntityInstance const& other) noexcept = default; + + // EDIT instances can be converted to "read" Instances of same type + template > + constexpr explicit EntityInstance(EntityInstance const& other) noexcept { + mInstance = other.asValue(); + } + template > + EntityInstance& operator=(EntityInstance const& other) noexcept { + mInstance = other.asValue(); + return *this; + } + + // Instances can be compared + constexpr bool operator!=(EntityInstance e) const { return mInstance != e.mInstance; } + constexpr bool operator==(EntityInstance e) const { return mInstance == e.mInstance; } + + // Instances can be sorted + constexpr bool operator<(EntityInstance e) const { return mInstance < e.mInstance; } + constexpr bool operator<=(EntityInstance e) const { return mInstance <= e.mInstance; } + constexpr bool operator>(EntityInstance e) const { return mInstance > e.mInstance; } + constexpr bool operator>=(EntityInstance e) const { return mInstance >= e.mInstance; } + + // and we can iterate + constexpr EntityInstance& operator++() noexcept { ++mInstance; return *this; } + constexpr EntityInstance& operator--() noexcept { --mInstance; return *this; } + constexpr const EntityInstance operator++(int) const noexcept { return EntityInstance{ mInstance + 1 }; } + constexpr const EntityInstance operator--(int) const noexcept { return EntityInstance{ mInstance - 1 }; } + + + // return a value for this Instance (mostly needed for debugging + constexpr uint32_t asValue() const noexcept { return mInstance; } + + // auto convert to Type, so it can be used as an index + constexpr operator Type() const noexcept { return mInstance; } // NOLINT(google-explicit-constructor) + + // conversion from Type so we can initialize from an index + constexpr EntityInstance(Type value) noexcept { mInstance = value; } // NOLINT(google-explicit-constructor) +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITYINSTANCE_H diff --git a/package/android/libs/filament/include/utils/EntityManager.h b/package/android/libs/filament/include/utils/EntityManager.h new file mode 100644 index 00000000..5e2eaa1b --- /dev/null +++ b/package/android/libs/filament/include/utils/EntityManager.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITYMANAGER_H +#define TNT_UTILS_ENTITYMANAGER_H + +#include +#include + +#include +#include +#include + +#ifndef FILAMENT_UTILS_TRACK_ENTITIES +#define FILAMENT_UTILS_TRACK_ENTITIES false +#endif + +#if FILAMENT_UTILS_TRACK_ENTITIES +#include +#include +#endif + +namespace utils { + +class UTILS_PUBLIC EntityManager { +public: + // Get the global EntityManager. It is recommended to cache this value. + // Thread Safe. + static EntityManager& get() noexcept; + + class Listener { + public: + virtual void onEntitiesDestroyed(size_t n, Entity const* entities) noexcept = 0; + protected: + virtual ~Listener() noexcept; + }; + + // maximum number of entities that can exist at the same time + static size_t getMaxEntityCount() noexcept { + // because index 0 is reserved, we only have 2^GENERATION_SHIFT - 1 valid indices + return RAW_INDEX_COUNT - 1; + } + + // number of active Entities + size_t getEntityCount() const noexcept; + + // Create n entities. Thread safe. + void create(size_t n, Entity* entities); + + // destroys n entities. Thread safe. + void destroy(size_t n, Entity* entities) noexcept; + + // Create a new Entity. Thread safe. + // Return Entity.isNull() if the entity cannot be allocated. + Entity create() { + Entity e; + create(1, &e); + return e; + } + + // Destroys an Entity. Thread safe. + void destroy(Entity e) noexcept { + destroy(1, &e); + } + + // Return whether the given Entity has been destroyed (false) or not (true). + // Thread safe. + bool isAlive(Entity e) const noexcept { + assert(getIndex(e) < RAW_INDEX_COUNT); + return (!e.isNull()) && (getGeneration(e) == mGens[getIndex(e)]); + } + + // Registers a listener to be called when an entity is destroyed. Thread safe. + // If the listener is already registered, this method has no effect. + void registerListener(Listener* l) noexcept; + + // unregisters a listener. + void unregisterListener(Listener* l) noexcept; + + + /* no user serviceable parts below */ + + // current generation of the given index. Use for debugging and testing. + uint8_t getGenerationForIndex(size_t index) const noexcept { + return mGens[index]; + } + + // singleton, can't be copied + EntityManager(const EntityManager& rhs) = delete; + EntityManager& operator=(const EntityManager& rhs) = delete; + +#if FILAMENT_UTILS_TRACK_ENTITIES + std::vector getActiveEntities() const; + void dumpActiveEntities(utils::io::ostream& out) const; +#endif + +private: + friend class EntityManagerImpl; + EntityManager(); + ~EntityManager(); + + // GENERATION_SHIFT determines how many simultaneous Entities are available, the + // minimum memory requirement is 2^GENERATION_SHIFT bytes. + static constexpr const int GENERATION_SHIFT = 17; + static constexpr const size_t RAW_INDEX_COUNT = (1 << GENERATION_SHIFT); + static constexpr const Entity::Type INDEX_MASK = (1 << GENERATION_SHIFT) - 1u; + + static inline Entity::Type getGeneration(Entity e) noexcept { + return e.getId() >> GENERATION_SHIFT; + } + static inline Entity::Type getIndex(Entity e) noexcept { + return e.getId() & INDEX_MASK; + } + static inline Entity::Type makeIdentity(Entity::Type g, Entity::Type i) noexcept { + return (g << GENERATION_SHIFT) | (i & INDEX_MASK); + } + + // stores the generation of each index. + uint8_t * const mGens; +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITYMANAGER_H diff --git a/package/android/libs/filament/include/utils/FixedCapacityVector.h b/package/android/libs/filament/include/utils/FixedCapacityVector.h new file mode 100644 index 00000000..f3990124 --- /dev/null +++ b/package/android/libs/filament/include/utils/FixedCapacityVector.h @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_FIXEDCAPACITYVECTOR_H +#define TNT_UTILS_FIXEDCAPACITYVECTOR_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef NDEBUG +#define FILAMENT_FORCE_CAPACITY_CHECK true +#else +#define FILAMENT_FORCE_CAPACITY_CHECK false +#endif + +namespace utils { + +/** + * FixedCapacityVector is (almost) a drop-in replacement for std::vector<> except it has a + * fixed capacity decided at runtime. The vector storage is never reallocated unless reserve() + * is called. Operations that add elements to the vector can fail if there is not enough + * capacity. + * + * An empty vector with a given capacity is created with + * FixedCapacityVector::with_capacity( capacity ); + * + * NOTE: When passing an initial size into the FixedCapacityVector constructor, default construction + * of the elements is skipped when their construction is trivial. This behavior is different from + * std::vector. e.g., std::vector(4) constructs 4 zeros while FixedCapacityVector(4) + * allocates 4 uninitialized values. Note that zero initialization is easily achieved by passing in + * the optional value argument, e.g. FixedCapacityVector(4, 0) or foo.resize(4, 0). + */ +template, bool CapacityCheck = true> +class UTILS_PUBLIC FixedCapacityVector { +public: + using allocator_type = A; + using value_type = T; + using reference = T&; + using const_reference = T const&; + using size_type = uint32_t; + using difference_type = int32_t; + using pointer = T*; + using const_pointer = T const*; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + +private: + using storage_traits = std::allocator_traits; + +public: + /** returns an empty vector with the specified capacity */ + static FixedCapacityVector with_capacity( + size_type capacity, const allocator_type& allocator = allocator_type()) { + return FixedCapacityVector(construct_with_capacity, capacity, allocator); + } + + FixedCapacityVector() = default; + + explicit FixedCapacityVector(const allocator_type& allocator) noexcept + : mCapacityAllocator({}, allocator) { + } + + explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type()) + : mSize(size), + mCapacityAllocator(size, allocator) { + mData = this->allocator().allocate(this->capacity()); + construct(begin(), end()); + } + + FixedCapacityVector(std::initializer_list list, + const allocator_type& alloc = allocator_type()) + : mSize(list.size()), + mCapacityAllocator(list.size(), alloc) { + mData = this->allocator().allocate(this->capacity()); + std::uninitialized_copy(list.begin(), list.end(), begin()); + } + + FixedCapacityVector(size_type size, const_reference value, + const allocator_type& alloc = allocator_type()) + : mSize(size), + mCapacityAllocator(size, alloc) { + mData = this->allocator().allocate(this->capacity()); + construct(begin(), end(), value); + } + + FixedCapacityVector(FixedCapacityVector const& rhs) + : mSize(rhs.mSize), + mCapacityAllocator(rhs.capacity(), + storage_traits::select_on_container_copy_construction(rhs.allocator())) { + mData = allocator().allocate(capacity()); + std::uninitialized_copy(rhs.begin(), rhs.end(), begin()); + } + + FixedCapacityVector(FixedCapacityVector&& rhs) noexcept { + this->swap(rhs); + } + + ~FixedCapacityVector() noexcept { + destroy(begin(), end()); + allocator().deallocate(data(), capacity()); + } + + FixedCapacityVector& operator=(FixedCapacityVector const& rhs) { + if (this != &rhs) { + FixedCapacityVector t(rhs); + this->swap(t); + } + return *this; + } + + FixedCapacityVector& operator=(FixedCapacityVector&& rhs) noexcept { + this->swap(rhs); + return *this; + } + + allocator_type get_allocator() const noexcept { + return mCapacityAllocator.second(); + } + + // -------------------------------------------------------------------------------------------- + + iterator begin() noexcept { return data(); } + iterator end() noexcept { return data() + size(); } + const_iterator begin() const noexcept { return data(); } + const_iterator end() const noexcept { return data() + size(); } + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + const_reverse_iterator crend() const noexcept { return rend(); } + + // -------------------------------------------------------------------------------------------- + + size_type size() const noexcept { return mSize; } + size_type capacity() const noexcept { return mCapacityAllocator.first(); } + bool empty() const noexcept { return size() == 0; } + size_type max_size() const noexcept { + return std::min(storage_traits::max_size(allocator()), + std::numeric_limits::max()); + } + + // -------------------------------------------------------------------------------------------- + + reference operator[](size_type n) noexcept { + assert(n < size()); + return *(begin() + n); + } + + const_reference operator[](size_type n) const noexcept { + assert(n < size()); + return *(begin() + n); + } + + reference front() noexcept { return *begin(); } + const_reference front() const noexcept { return *begin(); } + reference back() noexcept { return *(end() - 1); } + const_reference back() const noexcept { return *(end() - 1); } + value_type* data() noexcept { return mData; } + const value_type* data() const noexcept { return mData; } + + // -------------------------------------------------------------------------------------------- + + void push_back(const_reference v) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, v); + } + + void push_back(value_type&& v) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, std::move(v)); + } + + template + reference emplace_back(ARGS&& ... args) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, std::forward(args)...); + return *pos; + } + + void pop_back() { + assert(!empty()); + --mSize; + destroy(end(), end() + 1); + } + + iterator insert(const_iterator position, const_reference v) { + if (position == end()) { + push_back(v); + } else { + assertCapacityForSize(size() + 1); + pointer p = const_cast(position); + move_range(p, end(), p + 1); + ++mSize; + // here we handle inserting an element of this vector! + const_pointer pv = std::addressof(v); + if (p <= pv && pv < end()) { + *p = *(pv + 1); + } else { + *p = v; + } + } + return const_cast(position); + } + + iterator insert(const_iterator position, value_type&& v) { + if (position == end()) { + push_back(std::move(v)); + } else { + assertCapacityForSize(size() + 1); + pointer p = const_cast(position); + move_range(p, end(), p + 1); + ++mSize; + *p = std::move(v); + } + return const_cast(position); + } + + iterator erase(const_iterator pos) { + assert(pos != end()); + return erase(pos, pos + 1); + } + + iterator erase(const_iterator first, const_iterator last) { + assert(first <= last); + auto e = std::move(const_cast(last), end(), const_cast(first)); + destroy(e, end()); + mSize -= std::distance(first, last); + return const_cast(first); + } + + void clear() noexcept { + destroy(begin(), end()); + mSize = 0; + } + + void resize(size_type count) { + assertCapacityForSize(count); + if constexpr(std::is_trivially_constructible_v && + std::is_trivially_destructible_v) { + // we check for triviality here so that the implementation could be non-inline + mSize = count; + } else { + resize_non_trivial(count); + } + } + + void resize(size_type count, const_reference v) { + assertCapacityForSize(count); + resize_non_trivial(count, v); + } + + void swap(FixedCapacityVector& other) { + using std::swap; + swap(mData, other.mData); + swap(mSize, other.mSize); + mCapacityAllocator.swap(other.mCapacityAllocator); + } + + UTILS_NOINLINE + void reserve(size_type c) { + if (c > capacity()) { + FixedCapacityVector t(construct_with_capacity, c, allocator()); + t.mSize = size(); + std::uninitialized_move(begin(), end(), t.begin()); + this->swap(t); + } + } + +private: + enum construct_with_capacity_tag{ construct_with_capacity }; + + FixedCapacityVector(construct_with_capacity_tag, + size_type capacity, const allocator_type& allocator = allocator_type()) + : mCapacityAllocator(capacity, allocator) { + mData = this->allocator().allocate(this->capacity()); + } + + allocator_type& allocator() noexcept { + return mCapacityAllocator.second(); + } + + allocator_type const& allocator() const noexcept { + return mCapacityAllocator.second(); + } + + iterator assertCapacityForSize(size_type s) { + if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) { + ASSERT_PRECONDITION(capacity() >= s, + "capacity exceeded: requested size %lu, available capacity %lu.", + (unsigned long)s, (unsigned long)capacity()); + } + return end(); + } + + inline void construct(iterator first, iterator last) noexcept { + // we check for triviality here so that the implementation could be non-inline + if constexpr(!std::is_trivially_constructible_v) { + construct_non_trivial(first, last); + } + } + + void construct(iterator first, iterator last, const_reference proto) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::construct(allocator(), first++, proto); + } + } + + // should this be NOINLINE? + void construct_non_trivial(iterator first, iterator last) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::construct(allocator(), first++); + } + } + + + inline void destroy(iterator first, iterator last) noexcept { + // we check for triviality here so that the implementation could be non-inline + if constexpr(!std::is_trivially_destructible_v) { + destroy_non_trivial(first, last); + } + } + + // should this be NOINLINE? + void destroy_non_trivial(iterator first, iterator last) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::destroy(allocator(), --last); + } + } + + // should this be NOINLINE? + void resize_non_trivial(size_type count) { + if (count > size()) { + construct(end(), begin() + count); + } else if (count < size()) { + destroy(begin() + count, end()); + } + mSize = count; + } + + // should this be NOINLINE? + void resize_non_trivial(size_type count, const_reference v) { + if (count > size()) { + construct(end(), begin() + count, v); + } else if (count < size()) { + destroy(begin() + count, end()); + } + mSize = count; + } + + // should this be NOINLINE? + void move_range(pointer s, pointer e, pointer to) { + if constexpr(std::is_trivially_copy_assignable_v + && std::is_trivially_destructible_v) { + // this generates memmove -- which doesn't happen otherwise + std::move_backward(s, e, to + std::distance(s, e)); + } else { + pointer our_end = end(); + difference_type n = our_end - to; // nb of elements to move by operator= + pointer i = s + n; // 1st element to move by move ctor + for (pointer d = our_end ; i < our_end ; ++i, ++d) { + storage_traits::construct(allocator(), d, std::move(*i)); + } + std::move_backward(s, s + n, our_end); + } + } + + template + class SizeTypeWrapper { + TYPE value{}; + public: + SizeTypeWrapper() noexcept = default; + SizeTypeWrapper(SizeTypeWrapper const& rhs) noexcept = default; + explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { } + SizeTypeWrapper& operator=(TYPE rhs) noexcept { value = rhs; return *this; } + SizeTypeWrapper& operator=(SizeTypeWrapper& rhs) noexcept = delete; + operator TYPE() const noexcept { return value; } + }; + + pointer mData{}; + size_type mSize{}; + compressed_pair, allocator_type> mCapacityAllocator{}; +}; + +} // namespace utils + +#endif // TNT_UTILS_FIXEDCAPACITYVECTOR_H diff --git a/package/android/libs/filament/include/utils/Invocable.h b/package/android/libs/filament/include/utils/Invocable.h new file mode 100644 index 00000000..49b43071 --- /dev/null +++ b/package/android/libs/filament/include/utils/Invocable.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef TNT_UTILS_INVOKABLE_H +#define TNT_UTILS_INVOKABLE_H + +#include +#include + +#include + +namespace utils { + +/* + * Invocable is a move-only general purpose function wrapper. Instances can + * store and invoke lambda expressions and other function objects. + * + * It is similar to std::function, with the following differences: + * - Invocable is move only. + * - Invocable can capture move only types. + * - No conversion between 'compatible' functions. + * - No small buffer optimization + */ + +// Helper for enabling methods if Fn matches the function signature +// requirements of the Invocable type. +#if __cplusplus >= 201703L +// only available on C++17 and up +template +using EnableIfFnMatchesInvocable = + std::enable_if_t && + std::is_same_v>, int>; +#else +template +using EnableIfFnMatchesInvocable = std::enable_if_t; +#endif + +template +class Invocable; + +template +class Invocable { +public: + // Creates an Invocable that does not contain a functor. + // Will evaluate to false. + Invocable() = default; + + ~Invocable() noexcept; + + // Creates an Invocable from the functor passed in. + template = 0> + Invocable(Fn&& fn) noexcept; // NOLINT(google-explicit-constructor) + + Invocable(const Invocable&) = delete; + Invocable(Invocable&& rhs) noexcept; + + Invocable& operator=(const Invocable&) = delete; + Invocable& operator=(Invocable&& rhs) noexcept; + + // Invokes the invocable with the args passed in. + // If the Invocable is empty, this will assert. + template + R operator()(OperatorArgs&& ... args); + template + R operator()(OperatorArgs&& ... args) const; + + // Evaluates to true if Invocable contains a functor, false otherwise. + explicit operator bool() const noexcept; + +private: + void* mInvocable = nullptr; + void (*mDeleter)(void*) = nullptr; + R (* mInvoker)(void*, Args...) = nullptr; +}; + +template +template> +Invocable::Invocable(Fn&& fn) noexcept + : mInvocable(new Fn(std::forward>(fn))), + mDeleter(+[](void* erased_invocable) { + auto typed_invocable = static_cast(erased_invocable); + delete typed_invocable; + }), + mInvoker(+[](void* erased_invocable, Args... args) -> R { + auto typed_invocable = static_cast(erased_invocable); + return (*typed_invocable)(std::forward(args)...); + }) +{ +} + +template +Invocable::~Invocable() noexcept { + if (mDeleter) { + mDeleter(mInvocable); + } +} + +template +Invocable::Invocable(Invocable&& rhs) noexcept + : mInvocable(rhs.mInvocable), + mDeleter(rhs.mDeleter), + mInvoker(rhs.mInvoker) { + rhs.mInvocable = nullptr; + rhs.mDeleter = nullptr; + rhs.mInvoker = nullptr; +} + +template +Invocable& Invocable::operator=(Invocable&& rhs) noexcept { + if (this != &rhs) { + std::swap(mInvocable, rhs.mInvocable); + std::swap(mDeleter, rhs.mDeleter); + std::swap(mInvoker, rhs.mInvoker); + } + return *this; +} + +template +template +R Invocable::operator()(OperatorArgs&& ... args) { + assert(mInvoker && mInvocable); + return mInvoker(mInvocable, std::forward(args)...); +} + +template +template +R Invocable::operator()(OperatorArgs&& ... args) const { + assert(mInvoker && mInvocable); + return mInvoker(mInvocable, std::forward(args)...); +} + +template +Invocable::operator bool() const noexcept { + return mInvoker != nullptr && mInvocable != nullptr; +} + +} // namespace utils + +#endif // TNT_UTILS_INVOKABLE_H diff --git a/package/android/libs/filament/include/utils/Log.h b/package/android/libs/filament/include/utils/Log.h new file mode 100644 index 00000000..77886426 --- /dev/null +++ b/package/android/libs/filament/include/utils/Log.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_LOG_H +#define TNT_UTILS_LOG_H + +#include +#include + +namespace utils { + +struct UTILS_PUBLIC Loggers { + // DEBUG level logging stream + io::ostream& d; + + // ERROR level logging stream + io::ostream& e; + + // WARNING level logging stream + io::ostream& w; + + // INFORMATION level logging stream + io::ostream& i; + + // VERBOSE level logging stream + io::ostream& v; +}; + +extern UTILS_PUBLIC Loggers const slog; + +} // namespace utils + +#endif // TNT_UTILS_LOG_H diff --git a/package/android/libs/filament/include/utils/Mutex.h b/package/android/libs/filament/include/utils/Mutex.h new file mode 100644 index 00000000..1de6257f --- /dev/null +++ b/package/android/libs/filament/include/utils/Mutex.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_UTILS_MUTEX_H +#define TNT_UTILS_MUTEX_H + +#if defined(__ANDROID__) +#include +#else +#include +#endif + +#endif // TNT_UTILS_MUTEX_H diff --git a/package/android/libs/filament/include/utils/NameComponentManager.h b/package/android/libs/filament/include/utils/NameComponentManager.h new file mode 100644 index 00000000..4ac7435a --- /dev/null +++ b/package/android/libs/filament/include/utils/NameComponentManager.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H +#define TNT_UTILS_NAMECOMPONENTMANAGER_H + +#include +#include +#include +#include +#include + +#include + +namespace utils { + +class EntityManager; + +/** + * \class NameComponentManager NameComponentManager.h utils/NameComponentManager.h + * \brief Allows clients to associate string labels with entities. + * + * To access the name of an existing entity, clients should first use NameComponentManager to get a + * temporary handle called an \em instance. Please note that instances are ephemeral; clients should + * store entities, not instances. + * + * Usage example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto names = new NameComponentManager(EntityManager::get()); + * names->addComponent(myEntity); + * names->setName(names->getInstance(myEntity), "Jeanne d'Arc"); + * ... + * printf("%s\n", names->getName(names->getInstance(myEntity)); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC NameComponentManager : private SingleInstanceComponentManager { +public: + using Instance = EntityInstance; + + /** + * Creates a new name manager associated with the given entity manager. + * + * Note that multiple string labels could be associated with each entity simply by + * creating multiple instances of NameComponentManager. + */ + explicit NameComponentManager(EntityManager& em); + ~NameComponentManager(); + + /** + * Checks if the given entity already has a name component. + */ + using SingleInstanceComponentManager::hasComponent; + + /** + * Gets a temporary handle that can be used to access the name. + * + * @return Non-zero handle if the entity has a name component, 0 otherwise. + */ + Instance getInstance(Entity e) const noexcept { + return { SingleInstanceComponentManager::getInstance(e) }; + } + + /** + * Adds a name component to the given entity if it doesn't already exist. + */ + void addComponent(Entity e); + + /** + * Removes the name component to the given entity if it exists. + */ + void removeComponent(Entity e); + + /** + * Stores a copy of the given string and associates it with the given instance. + */ + void setName(Instance instance, const char* name) noexcept; + + /** + * Retrieves the string associated with the given instance, or nullptr if none exists. + * + * @return pointer to the copy that was made during setName() + */ + const char* getName(Instance instance) const noexcept; + + void gc(EntityManager& em) noexcept { + SingleInstanceComponentManager::gc(em, [this](Entity e) { + removeComponent(e); + }); + } +}; + +} // namespace utils + +#endif // TNT_UTILS_NAMECOMPONENTMANAGER_H diff --git a/package/android/libs/filament/include/utils/Panic.h b/package/android/libs/filament/include/utils/Panic.h new file mode 100644 index 00000000..b4ec032c --- /dev/null +++ b/package/android/libs/filament/include/utils/Panic.h @@ -0,0 +1,563 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_PANIC_H +#define TNT_UTILS_PANIC_H + +#include +#include + +#include + +#ifdef __EXCEPTIONS +# define UTILS_EXCEPTIONS 1 +#else +#endif + +/** + * @defgroup errors Handling Catastrophic Failures (Panics) + * + * @brief Failure detection and reporting facilities + * + * ## What's a Panic? ## + * + * In the context of this document, a _panic_ is a type of error due to a _contract violation_, + * it shouldn't be confused with a _result_ or _status_ code. The POSIX API for instance, + * unfortunately often conflates the two. + * @see + * + * + * Here we give the following definition of a _panic_: + * + * 1. Failures to meet a function's own **postconditions**\n + * The function cannot establish one of its own postconditions, such as (but not limited to) + * producing a valid return value object. + * + * Often these failures are only detectable at runtime, for instance they can be caused by + * arithmetic errors, as it was the case for the Ariane 5 rocket. Ariane 5 crashed because it + * reused an inertial module from Ariane 4, which didn't account for the greater horizontal + * acceleration of Ariane 5 and caused an overflow in the computations. Ariane 4's module + * wasn't per-say buggy, but was improperly used and failed to meet, obviously, certain + * postconditions. + * @see + * + * 2. Failures to meet the **preconditions** of any of a function's callees\n + * The function cannot meet a precondition of another function it must call, such as a + * restriction on a parameter. + * + * Not to be confused with the case where the preconditions of a function are already + * violated upon entry, which indicates a programming error from the caller. + * + * Typically these failures can be avoided and arise because of programming errors. + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Failure reporting vs. handling ## + * + * Very often when a panic, as defined above, is detected, the program has little other choice + * but to terminate.\n + * Typically these situations can be handled by _assert()_. However, _assert()_ also conflates two + * very different concepts: detecting and handling failures.\n + * The place where a failure is detected is rarely the place where there is enough + * context to decide what to do. _assert()_ terminates the program which, may or may not be + * appropriate. At the very least the failure must be logged (which _assert()_ does in a crude way), + * but some other actions might need to happen, such as:\n + * + * - logging the failure in the system-wide logger + * - providing enough information in development builds to analyze/debug the problem + * - cleanly releasing some resources, such as communication channels with other processes\n + * e.g.: to avoid their pre- or postconditions from being violated as well. + * + * In some _rare_ cases, the failure might even be ignored altogether because it doesn't matter in + * the context where it happened. This decision clearly doesn't always lie at the failure-site. + * + * It is therefore important to separate failure detection from handling. + * + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Failure detection and handling facilities ## + * + * Clearly, catastrophic failures should be **rare**; in fact they should + * never happen, except possibly for "failures to meet a function's own postconditions", which + * may depend on external factors and should still be very rare. Yet, when a failure happens, it + * must be detected and handled appropriately.\n + * Since panics are rare, it is desirable that the handling mechanism be as unobtrusive + * as possible, without allowing such failures to go unnoticed or swallowed by mistake. Ideally, the + * programmer using an API should have nothing special to do to handle that API's failure + * conditions.\n\n + * + * An important feature of the Panic Handling facilities here is that **panics are not part of + * the API of a function or method**\n\n + * + * + * The panic handling facility has the following benefits: + * - provides an easy way to detect and report failure + * - separates failure detection from handling + * - makes it hard for detected failures to be ignored (i.e.: not handled) + * - doesn't add burden on the API design + * - doesn't add overhead (visual or otherwise) at call sites + * - has very little performance overhead for failure detection + * - has little to no performance impact for failure handling in the common (success) case + * - is flexible and extensible + * + * Since we have established that failures are **rare**, **exceptional** situations, it would be + * appropriate to handle them with an _assert_ mechanism and that's what the API below + * provides. However, under-the-hood it uses C++ exceptions as a means to separate + * _reporting_ from _handling_. + * + * \note On devices where exceptions are not supported or appropriate, these APIs can be turned + * into a regular _std::terminate()_. + * + * + * ASSERT_PRECONDITION(condition, format, ...) + * ASSERT_POSTCONDITION(condition, format, ...) + * ASSERT_ARITHMETIC(condition, format, ...) + * ASSERT_DESTRUCTOR(condition, format, ...) + * + * + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see ASSERT_DESTRUCTOR + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Writing code that can assert ## + * + * Because we've separated failure reporting from failure handling, there are some considerations + * that need to be thought about when writing code that calls the macros above (i.e.: the program + * won't terminate at the point where the failure is detected).\n\n + * + * + * ### Panic guarantees ### + * + * After the failure condition is reported by a function, additional guarantees may be provided + * with regards to the state of the program. The following four levels of guarantee are + * generally recognized, each of which is a strict superset of its successors: + * + * 1. Nothrow exception guarantee\n + * The function never asserts. e.g.: This should always be the case with destructors.\n\n + * + * 2. Strong exception guarantee\n + * If the function asserts, the state of the program is rolled back to the state just before + * the function call.\n\n + * + * 3. Basic exception guarantee\n + * If the function asserts, the program is in a valid state. It may require cleanup, + * but all invariants are intact.\n\n + * + * 4. No exception guarantee\n + * If the function asserts, the program may not be in a valid state: resource leaks, memory + * corruption, or other invariant-destroying failures may have occurred. + * + * In each function, give the **strongest** safety guarantee that won't penalize callers who + * don't need it, but **always give at least the basic guarantee**. The RAII (Resource + * Acquisition Is Initialization) pattern can help with achieving these guarantees. + * + * @see [RAII](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) + * + * ### Special considerations for Constructors ### + * + * Constructors are a bit special because if a failure occurs during their execution, the + * destructor won't be called (how could it? since the object wasn't constructed!). This can lead + * to leaked resources allocated in the constructor prior to the failure. Thankfully there is + * a nice C++ syntax to handle this case: + * + * @code + * Foo::Foo(size_t s) try : m_size(s), m_buf(new uint32_t[s]) { + * ASSERT_POSTCONDITION(s&0xF==0, + * "object size is %u, but must be multiple of 16", s); + * } catch (...) { + * delete [] m_buf; + * // the exception will be automatically re-thrown + * } + * @endcode + * + * Unfortunately, this usage leaks the underlying, exception-based, implementation of the + * panic handling macros. For this reason, it is best to keep constructors simple and guarantee + * they can't fail. An _init()_ function with a factory can be used for actual initialization. + * + * + * ### Special considerations for Destructors ### + * + * In C++ destructors cannot throw exceptions and since the above macros internally use exceptions + * they cannot be used in destructors. Doing so will result in immediate termination of the + * program by _std::terminate()_.\n + * It is therefore best to always guarantee that destructors won't fail. In case of such a + * failure in a destructor the ASSERT_DESTRUCTOR() macro can be used instead, it + * will log the failure but won't terminate the program, instead it'll proceed as if nothing + * happened. Generally this will result in some resource leak which, eventually, will cause + * another failure (typically a postcondition violation).\n\n + * + * Rationale for this behavior: There are fundamentally no way to report a failure from a + * destructor in C++, violently terminating the process is inadequate because it again conflates + * failure reporting and failure handling; for instance a failure in glDeleteTextures() shouldn't + * be necessarily fatal (certainly not without saving the user's data first). The alternative + * would be for the caller to swallow the failure entirely, but that's not great either because the + * failure would go unnoticed. The solution retained here is a compromise. + * + * @see ASSERT_DESTRUCTOR + * + * ### Testing Code that Uses Panics ### + * + * Since panics use exceptions for their underlying implementation, you can test code that uses + * panics with EXPECT_THROW by doing the following things: + * \li Set panic mode to THROW (default is TERMINATE) + * \li Pass Panic to EXPECT_THROW as the exception type + * + * Example code for your test file: + * + * @code + * #include // since your code uses panics, this should include utils/Panic.hpp + * + * using utils::Panic; + * + * TEST(MyClassTest, value_that_causes_panic) { + * EXPECT_THROW(MyClass::function(value_that_causes_panic), Panic); + * } + * + * // ... other tests ... + * + * int main(int argc, char** argv) { + * ::testing::InitGoogleTest(&argc, argv); + * Panic::setMode(Panic::Mode::THROW); + * return RUN_ALL_TESTS(); + * } + * @endcode + * + */ + +namespace utils { + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * \brief Base class of all exceptions thrown by all the ASSERT macros + * + * The Panic class provides the std::exception protocol, it is the base exception object + * used for all thrown exceptions. + */ +class UTILS_PUBLIC Panic { +public: + virtual ~Panic() noexcept; + + /** + * @return a detailed description of the error + * @see std::exception + */ + virtual const char* what() const noexcept = 0; + + /** + * Get the function name where the panic was detected + * @return a C string containing the function name where the panic was detected + */ + virtual const char* getFunction() const noexcept = 0; + + /** + * Get the file name where the panic was detected + * @return a C string containing the file name where the panic was detected + */ + virtual const char* getFile() const noexcept = 0; + + /** + * Get the line number in the file where the panic was detected + * @return an integer containing the line number in the file where the panic was detected + */ + virtual int getLine() const noexcept = 0; + + /** + * Logs this exception to the system-log + */ + virtual void log() const noexcept = 0; + + /** + * Get the CallStack when the panic was detected + * @return the CallStack when the panic was detected + */ + virtual const CallStack& getCallStack() const noexcept = 0; +}; + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * \brief Concrete implementation of the Panic interface. + * + * The TPanic<> class implements the std::exception protocol as well as the Panic + * interface common to all exceptions thrown by the framework. + */ +template +class UTILS_PUBLIC TPanic : public Panic { +public: + // std::exception protocol + const char* what() const noexcept override; + + // Panic interface + const char* getFunction() const noexcept override; + const char* getFile() const noexcept override; + int getLine() const noexcept override; + const CallStack& getCallStack() const noexcept override; + void log() const noexcept override; + + /** + * Depending on the mode set, either throws an exception of type T with the given reason plus + * extra information about the error-site, or logs the error and calls std::terminate(). + * This function never returns. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param format printf style string describing the error + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC + * @see setMode() + */ + static void panic(char const* function, char const* file, int line, const char* format, ...) + UTILS_NORETURN; + + /** + * Depending on the mode set, either throws an exception of type T with the given reason plus + * extra information about the error-site, or logs the error and calls std::terminate(). + * This function never returns. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param s std::string describing the error + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC + * @see setMode() + */ + static inline void panic(char const* function, char const* file, int line, const std::string& s) + UTILS_NORETURN { + panic(function, file, line, s.c_str()); + } + +protected: + /** + * Creates a Panic. + * @param reason a description of the cause of the error + */ + explicit TPanic(std::string reason); + + /** + * Creates a Panic with extra information about the error-site. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param reason a description of the cause of the error + */ + TPanic(char const* function, char const* file, int line, std::string reason); + + ~TPanic() override; + +private: + void buildMessage(); + + CallStack m_callstack; + std::string m_reason; + char const* const m_function = nullptr; + char const* const m_file = nullptr; + const int m_line = -1; + mutable std::string m_msg; +}; + +namespace details { +// these are private, don't use +void panicLog( + char const* function, char const* file, int line, const char* format, ...) noexcept; +} // namespace details + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * ASSERT_PRECONDITION uses this Panic to report a precondition failure. + * @see ASSERT_PRECONDITION + */ +class UTILS_PUBLIC PreconditionPanic : public TPanic { + // Programming error, can be avoided + // e.g.: invalid arguments + using TPanic::TPanic; + friend class TPanic; +}; + +/** + * @ingroup errors + * + * ASSERT_POSTCONDITION uses this Panic to report a postcondition failure. + * @see ASSERT_POSTCONDITION + */ +class UTILS_PUBLIC PostconditionPanic : public TPanic { + // Usually only detectable at runtime + // e.g.: dead-lock would occur, arithmetic errors + using TPanic::TPanic; + friend class TPanic; +}; + +/** + * @ingroup errors + * + * ASSERT_ARITHMETIC uses this Panic to report an arithmetic (postcondition) failure. + * @see ASSERT_ARITHMETIC + */ +class UTILS_PUBLIC ArithmeticPanic : public TPanic { + // A common case of post-condition error + // e.g.: underflow, overflow, internal computations errors + using TPanic::TPanic; + friend class TPanic; +}; + +// ----------------------------------------------------------------------------------------------- +} // namespace utils + +#ifndef NDEBUG +# define PANIC_FILE(F) (F) +# define PANIC_FUNCTION __PRETTY_FUNCTION__ +#else +# define PANIC_FILE(F) "" +# define PANIC_FUNCTION __func__ +#endif + +/** + * PANIC_PRECONDITION is a macro that reports a PreconditionPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_PRECONDITION(format, ...) \ + ::utils::PreconditionPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_POSTCONDITION is a macro that reports a PostconditionPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_POSTCONDITION(format, ...) \ + ::utils::PostconditionPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_ARITHMETIC is a macro that reports a ArithmeticPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_ARITHMETIC(format, ...) \ + ::utils::ArithmeticPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_LOG is a macro that logs a Panic, and continues as usual. + * @param format printf-style string describing the error in more details + */ +#define PANIC_LOG(format, ...) \ + ::utils::details::panicLog(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * @ingroup errors + * + * ASSERT_PRECONDITION is a macro that checks the given condition and reports a PreconditionPanic + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + */ +#define ASSERT_PRECONDITION(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__) : (void)0) + +#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG) +#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__), false : true) +#else +#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true) +#endif + + +/** + * @ingroup errors + * + * ASSERT_POSTCONDITION is a macro that checks the given condition and reports a PostconditionPanic + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + * + * Example: + * @code + * int& Foo::operator[](size_t index) { + * ASSERT_POSTCONDITION(index=0 && v<65536, "overflow occurred"); + * return uint32_t(v); + * } + * @endcode + */ +#define ASSERT_ARITHMETIC(cond, format, ...) \ + (!(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__) : (void)0) + +#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG) +#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__), false : true) +#else +#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true) +#endif + +/** + * @ingroup errors + * + * ASSERT_DESTRUCTOR is a macro that checks the given condition and logs an error + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + * + * @warning Use this macro if a destructor can fail, which should be avoided at all costs. + * Unlike the other ASSERT macros, this will never result in the process termination. Instead, + * the error will be logged and the program will continue as if nothing happened. + * + * Example: + * @code + * Foo::~Foo() { + * glDeleteTextures(1, &m_texture); + * GLint err = glGetError(); + * ASSERT_DESTRUCTOR(err == GL_NO_ERROR, "cannot free GL resource!"); + * } + * @endcode + */ +#define ASSERT_DESTRUCTOR(cond, format, ...) (!(cond) ? PANIC_LOG(format, ##__VA_ARGS__) : (void)0) + +#endif // TNT_UTILS_PANIC_H diff --git a/package/android/libs/filament/include/utils/Path.h b/package/android/libs/filament/include/utils/Path.h new file mode 100644 index 00000000..48195b26 --- /dev/null +++ b/package/android/libs/filament/include/utils/Path.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_PATH_H +#define TNT_UTILS_PATH_H + +#include + +#include +#include +#include + +namespace utils { + +/** + * An abstract representation of file and directory paths. + */ +class UTILS_PUBLIC Path { +public: + /** + * Creates a new empty path. + */ + Path() = default; + ~Path() = default; + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a non-null pathname string + */ + Path(const char* pathname); + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a pathname string view + */ + Path(std::string_view pathname); + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a pathname string + */ + Path(const std::string& pathname); + + /** + * Tests whether the file or directory denoted by this abstract + * pathname exists. + * + * @return true if the file or directory denoted by this + * abstract pathname exists, false otherwise + */ + bool exists() const; + + /** + * Tests whether this abstract pathname represents a regular file. + * This method can only return true if the path exists. + * + * @return true if this pathname represents an existing file, + * false if the path doesn't exist or represents something + * else (directory, symlink, etc.) + */ + bool isFile() const; + + /** + * Tests whether this abstract pathname represents a directory. + * This method can only return true if the path exists. + * + * @return true if this pathname represents an existing directory, + * false if the path doesn't exist or represents a file + */ + bool isDirectory() const; + + /** + * Tests whether this path is empty. An empty path does not + * exist. + * + * @return true if the underlying abstract pathname is empty, + * false otherwise + */ + bool isEmpty() const { return m_path.empty(); } + + const char* c_str() const { return m_path.c_str(); } + + /** + * Replaces the abstract pathname of this object with the + * specified pathname. + * + * @param pathname a pathname string + */ + void setPath(const std::string& pathname) { + m_path = getCanonicalPath(pathname); + } + + /** + * @return the canonical pathname this path represents + */ + const std::string& getPath() const { return m_path; } + + /** + * Returns the parent of this path as Path. + * @return a new path containing the parent of this path + */ + Path getParent() const; + + /** + * Returns ancestor path where "0" is the immediate parent. + * @return a new path containing the ancestor of this path + */ + Path getAncestor(int n) const; + + /** + * Returns the name of the file or directory represented by + * this abstract pathname. + * + * @return the name of the file or directory represented by + * this abstract pathname, or an empty string if + * this path is empty + */ + std::string getName() const; + + /** + * Returns the name of the file or directory represented by + * this abstract pathname without its extension. + * + * @return the name of the file or directory represented by + * this abstract pathname, or an empty string if + * this path is empty + */ + std::string getNameWithoutExtension() const; + + /** + * Returns the file extension (after the ".") if one is present. + * Returns the empty string if no filename is present or if the + * path is a directory. + * + * @return the file extension (if one is present and + * this is not a directory), else the empty string. + */ + std::string getExtension() const; + + /** + * Returns the absolute representation of this path. + * If this path's pathname starts with a leading '/', + * the returned path is equal to this path. Otherwise, + * this path's pathname is concatenated with the current + * working directory and the result is returned. + * + * @return a new path containing the absolute representation + * of this path + */ + Path getAbsolutePath() const; + + /** + * @return true if this abstract pathname is not empty + * and starts with a leading '/', false otherwise + */ + bool isAbsolute() const; + + /** + * Splits this object's abstract pathname in a vector of file + * and directory name. If the underlying abstract pathname + * starts with a '/', the returned vector's first element + * will be the string "/". + * + * @return a vector of strings, empty if this path is empty + */ + std::vector split() const; + + /** + * Concatenates the specified path with this path in a new + * path object. + * + * @note if the pathname to concatenate with starts with + * a leading '/' then that pathname is returned without + * being concatenated to this object's pathname. + * + * @param path the path to concatenate with + * + * @return the concatenation of the two paths + */ + Path concat(const Path& path) const; + + /** + * Concatenates the specified path with this path and + * stores the result in this path. + * + * @note if the pathname to concatenate with starts with + * a leading '/' then that pathname replaces this object's + * pathname. + * + * @param path the path to concatenate with + */ + void concatToSelf(const Path& path); + + operator std::string const&() const { return m_path; } + + Path operator+(const Path& rhs) const { return concat(rhs); } + Path& operator+=(const Path& rhs) { + concatToSelf(rhs); + return *this; + } + + bool operator==(const Path& rhs) const { return m_path == rhs.m_path; } + bool operator!=(const Path& rhs) const { return m_path != rhs.m_path; } + + bool operator<(const Path& rhs) const { return m_path < rhs.m_path; } + bool operator>(const Path& rhs) const { return m_path > rhs.m_path; } + + friend std::ostream& operator<<(std::ostream& os, const Path& path); + + /** + * Returns a canonical copy of the specified pathname by removing + * unnecessary path segments such as ".", ".." and "/". + * + * @param pathname a pathname string + * + * @return the canonical representation of the specified pathname + */ + static std::string getCanonicalPath(const std::string& pathname); + + /** + * This method is equivalent to calling root.concat(leaf). + */ + static Path concat(const std::string& root, const std::string& leaf); + + /** + * @return a path representing the current working directory + */ + static Path getCurrentDirectory(); + + /** + * @return a path representing the current executable + */ + static Path getCurrentExecutable(); + + /** + * @return a path representing a directory where temporary files can be stored + */ + static Path getTemporaryDirectory(); + + /** + * @return a path representing a directory where settings files can be stored, + * it is recommended to append an app specific folder name to that path + */ + static Path getUserSettingsDirectory(); + + /** + * Creates a directory denoted by the given path. + * This is not recursive and doesn't create intermediate directories. + * + * @return True if directory was successfully created. + * When false, errno should have details on actual error. + */ + bool mkdir() const; + + /** + * Creates a directory denoted by the given path. + * This is recursive and parent directories will be created if they do not + * exist. + * + * @return True if directory was successfully created or already exists. + * When false, errno should have details on actual error. + */ + bool mkdirRecursive() const; + + /** + * Deletes this file. + * + * @return True if file was successfully deleted. + * When false, errno should have details on actual error. + */ + bool unlinkFile(); + + /** + * Lists the contents of this directory, skipping hidden files. + * + * @return A vector of paths of the contents of the directory. If the path points to a file, + * nonexistent directory, or empty directory, an empty vector is returned. + */ + std::vector listContents() const; + +private: + std::string m_path; +}; + +} // namespace utils + +#endif // TNT_UTILS_PATH_H diff --git a/package/android/libs/filament/include/utils/PrivateImplementation-impl.h b/package/android/libs/filament/include/utils/PrivateImplementation-impl.h new file mode 100644 index 00000000..3488b5ae --- /dev/null +++ b/package/android/libs/filament/include/utils/PrivateImplementation-impl.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef UTILS_PRIVATEIMPLEMENTATION_IMPL_H +#define UTILS_PRIVATEIMPLEMENTATION_IMPL_H + +/* + * This looks like a header file, but really it acts as a .cpp, because it's used to + * explicitly instantiate the methods of PrivateImplementation<> + */ + +#include + +#include + +namespace utils { + +template +PrivateImplementation::PrivateImplementation() noexcept + : mImpl(new T) { +} + +template +template +PrivateImplementation::PrivateImplementation(ARGS&& ... args) noexcept + : mImpl(new T(std::forward(args)...)) { +} + +template +PrivateImplementation::~PrivateImplementation() noexcept { + delete mImpl; +} + +#ifndef UTILS_PRIVATE_IMPLEMENTATION_NON_COPYABLE + +template +PrivateImplementation::PrivateImplementation(PrivateImplementation const& rhs) noexcept + : mImpl(new T(*rhs.mImpl)) { +} + +template +PrivateImplementation& PrivateImplementation::operator=(PrivateImplementation const& rhs) noexcept { + if (this != &rhs) { + *mImpl = *rhs.mImpl; + } + return *this; +} + +#endif + +} // namespace utils + +#endif // UTILS_PRIVATEIMPLEMENTATION_IMPL_H diff --git a/package/android/libs/filament/include/utils/PrivateImplementation.h b/package/android/libs/filament/include/utils/PrivateImplementation.h new file mode 100644 index 00000000..ee0ac48a --- /dev/null +++ b/package/android/libs/filament/include/utils/PrivateImplementation.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef UTILS_PRIVATEIMPLEMENTATION_H +#define UTILS_PRIVATEIMPLEMENTATION_H + +#include + +namespace utils { + +/** + * \privatesection + * PrivateImplementation is used to hide the implementation details of a class and ensure a higher + * level of backward binary compatibility. + * The actual implementation is in src/PrivateImplementation-impl.h" + */ +template +class PrivateImplementation { +public: + // none of these methods must be implemented inline because it's important that their + // implementation be hidden from the public headers. + template + explicit PrivateImplementation(ARGS&& ...) noexcept; + PrivateImplementation() noexcept; + ~PrivateImplementation() noexcept; + PrivateImplementation(PrivateImplementation const& rhs) noexcept; + PrivateImplementation& operator = (PrivateImplementation const& rhs) noexcept; + + // move ctor and copy operator can be implemented inline and don't need to be exported + PrivateImplementation(PrivateImplementation&& rhs) noexcept : mImpl(rhs.mImpl) { rhs.mImpl = nullptr; } + PrivateImplementation& operator = (PrivateImplementation&& rhs) noexcept { + auto temp = mImpl; + mImpl = rhs.mImpl; + rhs.mImpl = temp; + return *this; + } + +protected: + T* mImpl = nullptr; + inline T* operator->() noexcept { return mImpl; } + inline T const* operator->() const noexcept { return mImpl; } +}; + +} // namespace utils + +#endif // UTILS_PRIVATEIMPLEMENTATION_H diff --git a/package/android/libs/filament/include/utils/SingleInstanceComponentManager.h b/package/android/libs/filament/include/utils/SingleInstanceComponentManager.h new file mode 100644 index 00000000..ddd538f5 --- /dev/null +++ b/package/android/libs/filament/include/utils/SingleInstanceComponentManager.h @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H +#define TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace utils { + +class EntityManager; + +/* + * Helper class to create single instance component managers. + * + * This handles the component's storage as a structure-of-arrays, as well + * as the garbage collection. + * + * This is intended to be used as base class for a real component manager. When doing so, + * and the real component manager is a public API, make sure to forward the public methods + * to the implementation. + * + */ +template +class UTILS_PUBLIC SingleInstanceComponentManager { +private: + + // this is just to avoid using std::default_random_engine, since we're in a public header. + class default_random_engine { + uint32_t mState = 1u; // must be 0 < seed < 0x7fffffff + public: + inline uint32_t operator()() noexcept { + return mState = uint32_t((uint64_t(mState) * 48271u) % 0x7fffffffu); + } + }; + +protected: + static constexpr size_t ENTITY_INDEX = sizeof ... (Elements); + + +public: + using SoA = StructureOfArrays; + + using Structure = typename SoA::Structure; + + using Instance = EntityInstanceBase::Type; + + SingleInstanceComponentManager() noexcept { + // We always start with a dummy entry because index=0 is reserved. The component + // at index = 0, is guaranteed to be default-initialized. + // Sub-classes can use this to their advantage. + mData.push_back(Structure{}); + } + + SingleInstanceComponentManager(SingleInstanceComponentManager&&) noexcept {/* = default */} + SingleInstanceComponentManager& operator=(SingleInstanceComponentManager&&) noexcept {/* = default */} + ~SingleInstanceComponentManager() noexcept = default; + + // not copyable + SingleInstanceComponentManager(SingleInstanceComponentManager const& rhs) = delete; + SingleInstanceComponentManager& operator=(SingleInstanceComponentManager const& rhs) = delete; + + + // returns true if the given Entity has a component of this Manager + bool hasComponent(Entity e) const noexcept { + return getInstance(e) != 0; + } + + // Get instance of this Entity to be used to retrieve components + UTILS_NOINLINE + Instance getInstance(Entity e) const noexcept { + auto const& map = mInstanceMap; + // find() generates quite a bit of code + auto pos = map.find(e); + return pos != map.end() ? pos->second : 0; + } + + // Returns the number of components (i.e. size of each array) + size_t getComponentCount() const noexcept { + // The array as an extra dummy component at index 0, so the visible count is 1 less. + return mData.size() - 1; + } + + bool empty() const noexcept { + return getComponentCount() == 0; + } + + utils::Entity const* getEntities() const noexcept { + return data() + 1; + } + + Entity getEntity(Instance i) const noexcept { + return elementAt(i); + } + + // Add a component to the given Entity. If the entity already has a component from this + // manager, this function is a no-op. + // This invalidates all pointers components. + inline Instance addComponent(Entity e); + + // Removes a component from the given entity. + // This invalidates all pointers components. + inline Instance removeComponent(Entity e); + + // return the first instance + Instance begin() const noexcept { return 1u; } + + // return the past-the-last instance + Instance end() const noexcept { return Instance(begin() + getComponentCount()); } + + // return a pointer to the first element of the ElementIndex'th array + template + typename SoA::template TypeAt* begin() noexcept { + return mData.template data() + 1; + } + + template + typename SoA::template TypeAt const* begin() const noexcept { + return mData.template data() + 1; + } + + // return a pointer to the past-the-end element of the ElementIndex'th array + template + typename SoA::template TypeAt* end() noexcept { + return begin() + getComponentCount(); + } + + template + typename SoA::template TypeAt const* end() const noexcept { + return begin() + getComponentCount(); + } + + // return a Slice<> + template + Slice> slice() noexcept { + return { begin(), end() }; + } + + template + Slice> slice() const noexcept { + return { begin(), end() }; + } + + // return a reference to the index'th element of the ElementIndex'th array + template + typename SoA::template TypeAt& elementAt(Instance index) noexcept { + assert(index); + return data()[index]; + } + + template + typename SoA::template TypeAt const& elementAt(Instance index) const noexcept { + assert(index); + return data()[index]; + } + + // returns a pointer to the RAW ARRAY of components including the first dummy component + // Use with caution. + template + typename SoA::template TypeAt const* raw_array() const noexcept { + return data(); + } + + // We need our own version of Field because mData is private + template + struct Field : public SoA::template Field { + Field(SingleInstanceComponentManager& soa, EntityInstanceBase::Type i) noexcept + : SoA::template Field{ soa.mData, i } { + } + using SoA::template Field::operator =; + }; + +protected: + template + typename SoA::template TypeAt* data() noexcept { + return mData.template data(); + } + + template + typename SoA::template TypeAt const* data() const noexcept { + return mData.template data(); + } + + // swap only internals + void swap(Instance i, Instance j) noexcept { + assert(i); + assert(j); + if (i && j) { + // update the index map + auto& map = mInstanceMap; + Entity& ei = elementAt(i); + Entity& ej = elementAt(j); + std::swap(ei, ej); + if (ei) { + map[ei] = i; + } + if (ej) { + map[ej] = j; + } + } + } + + template + void gc(const EntityManager& em, + REMOVE&& removeComponent) noexcept { + gc(em, 4, std::forward(removeComponent)); + } + + template + void gc(const EntityManager& em, size_t ratio, + REMOVE&& removeComponent) noexcept { + Entity const* const pEntities = begin(); + size_t count = getComponentCount(); + size_t aliveInARow = 0; + default_random_engine& rng = mRng; + UTILS_NOUNROLL + while (count && aliveInARow < ratio) { + assert_invariant(count == getComponentCount()); + // note: using the modulo favorizes lower number + size_t const i = rng() % count; + Entity const entity = pEntities[i]; + assert_invariant(entity); + if (UTILS_LIKELY(em.isAlive(entity))) { + ++aliveInARow; + continue; + } + removeComponent(entity); + aliveInARow = 0; + count--; + } + } + +protected: + SoA mData; + +private: + // maps an entity to an instance index + tsl::robin_map mInstanceMap; + default_random_engine mRng; +}; + +// Keep these outside of the class because CLion has trouble parsing them +template +typename SingleInstanceComponentManager::Instance +SingleInstanceComponentManager::addComponent(Entity e) { + Instance ci = 0; + if (!e.isNull()) { + if (!hasComponent(e)) { + // this is like a push_back(e); + mData.push_back(Structure{}).template back() = e; + // index 0 is used when the component doesn't exist + ci = Instance(mData.size() - 1); + mInstanceMap[e] = ci; + } else { + // if the entity already has this component, just return its instance + ci = mInstanceMap[e]; + } + } + assert(ci != 0); + return ci; +} + +// Keep these outside of the class because CLion has trouble parsing them +template +typename SingleInstanceComponentManager::Instance +SingleInstanceComponentManager::removeComponent(Entity e) { + auto& map = mInstanceMap; + auto pos = map.find(e); + if (UTILS_LIKELY(pos != map.end())) { + size_t index = pos->second; + assert(index != 0); + size_t last = mData.size() - 1; + if (last != index) { + // move the last item to where we removed this component, as to keep + // the array tightly packed. + mData.forEach([index, last](auto* p) { + p[index] = std::move(p[last]); + }); + + Entity lastEntity = mData.template elementAt(index); + map[lastEntity] = index; + } + mData.pop_back(); + map.erase(pos); + return last; + } + return 0; +} + + +} // namespace filament + +#endif // TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H diff --git a/package/android/libs/filament/include/utils/Slice.h b/package/android/libs/filament/include/utils/Slice.h new file mode 100644 index 00000000..444a3b27 --- /dev/null +++ b/package/android/libs/filament/include/utils/Slice.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_SLICE_H +#define TNT_UTILS_SLICE_H + +#include + +#include + +#include +#include + +namespace utils { + +/* + * A fixed-size slice of a container + */ +template +class Slice { +public: + using iterator = T*; + using const_iterator = T const*; + using value_type = T; + using reference = T&; + using const_reference = T const&; + using pointer = T*; + using const_pointer = T const*; + using size_type = size_t; + + Slice() noexcept = default; + + Slice(const_iterator begin, const_iterator end) noexcept + : mBegin(const_cast(begin)), + mEnd(const_cast(end)) { + } + + Slice(const_pointer begin, size_type count) noexcept + : mBegin(const_cast(begin)), + mEnd(mBegin + count) { + } + + Slice(Slice const& rhs) noexcept = default; + Slice(Slice&& rhs) noexcept = default; + Slice& operator=(Slice const& rhs) noexcept = default; + Slice& operator=(Slice&& rhs) noexcept = default; + + void set(pointer begin, size_type count) UTILS_RESTRICT noexcept { + mBegin = begin; + mEnd = begin + count; + } + + void set(iterator begin, iterator end) UTILS_RESTRICT noexcept { + mBegin = begin; + mEnd = end; + } + + void swap(Slice& rhs) UTILS_RESTRICT noexcept { + std::swap(mBegin, rhs.mBegin); + std::swap(mEnd, rhs.mEnd); + } + + void clear() UTILS_RESTRICT noexcept { + mBegin = nullptr; + mEnd = nullptr; + } + + // size + size_t size() const UTILS_RESTRICT noexcept { return mEnd - mBegin; } + size_t sizeInBytes() const UTILS_RESTRICT noexcept { return size() * sizeof(T); } + bool empty() const UTILS_RESTRICT noexcept { return size() == 0; } + + // iterators + iterator begin() UTILS_RESTRICT noexcept { return mBegin; } + const_iterator begin() const UTILS_RESTRICT noexcept { return mBegin; } + const_iterator cbegin() const UTILS_RESTRICT noexcept { return this->begin(); } + iterator end() UTILS_RESTRICT noexcept { return mEnd; } + const_iterator end() const UTILS_RESTRICT noexcept { return mEnd; } + const_iterator cend() const UTILS_RESTRICT noexcept { return this->end(); } + + // data access + reference operator[](size_t n) UTILS_RESTRICT noexcept { + assert(n < size()); + return mBegin[n]; + } + + const_reference operator[](size_t n) const UTILS_RESTRICT noexcept { + assert(n < size()); + return mBegin[n]; + } + + reference at(size_t n) UTILS_RESTRICT noexcept { + return operator[](n); + } + + const_reference at(size_t n) const UTILS_RESTRICT noexcept { + return operator[](n); + } + + reference front() UTILS_RESTRICT noexcept { + assert(!empty()); + return *mBegin; + } + + const_reference front() const UTILS_RESTRICT noexcept { + assert(!empty()); + return *mBegin; + } + + reference back() UTILS_RESTRICT noexcept { + assert(!empty()); + return *(this->end() - 1); + } + + const_reference back() const UTILS_RESTRICT noexcept { + assert(!empty()); + return *(this->end() - 1); + } + + pointer data() UTILS_RESTRICT noexcept { + return this->begin(); + } + + const_pointer data() const UTILS_RESTRICT noexcept { + return this->begin(); + } + +protected: + iterator mBegin = nullptr; + iterator mEnd = nullptr; +}; + +} // namespace utils + +#endif // TNT_UTILS_SLICE_H diff --git a/package/android/libs/filament/include/utils/StructureOfArrays.h b/package/android/libs/filament/include/utils/StructureOfArrays.h new file mode 100644 index 00000000..a4309584 --- /dev/null +++ b/package/android/libs/filament/include/utils/StructureOfArrays.h @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_STRUCTUREOFARRAYS_H +#define TNT_UTILS_STRUCTUREOFARRAYS_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include // note: this is safe, see how std::array is used below (inline / private) +#include +#include // for std::random_access_iterator_tag +#include +#include + +namespace utils { + +template +class StructureOfArraysBase { + // number of elements + static constexpr const size_t kArrayCount = sizeof...(Elements); + +public: + using SoA = StructureOfArraysBase; + + using Structure = std::tuple; + + // Type of the Nth array + template + using TypeAt = typename std::tuple_element_t; + + // Number of arrays + static constexpr size_t getArrayCount() noexcept { return kArrayCount; } + + // Size needed to store "size" array elements + static size_t getNeededSize(size_t size) noexcept { + return getOffset(kArrayCount - 1, size) + sizeof(TypeAt) * size; + } + + // -------------------------------------------------------------------------------------------- + + class IteratorValue; + template class Iterator; + using iterator = Iterator; + using const_iterator = Iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + + /* + * An object that represents a reference to the type dereferenced by iterator. + * In other words, it's the return type of iterator::operator*(), and since it + * cannot be a C++ reference (&), it's an object that acts like it. + */ + class IteratorValueRef { + friend class IteratorValue; + friend iterator; + friend const_iterator; + StructureOfArraysBase* const UTILS_RESTRICT soa; + size_t const index; + + IteratorValueRef(StructureOfArraysBase* soa, size_t index) : soa(soa), index(index) { } + + // assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference) + template + IteratorValueRef& assign(IteratorValue const& rhs, std::index_sequence); + + // assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference) + template + IteratorValueRef& assign(IteratorValue&& rhs, std::index_sequence) noexcept; + + // objects pointed to by reference can be swapped, so provide the special swap() function. + friend void swap(IteratorValueRef lhs, IteratorValueRef rhs) { + lhs.soa->swap(lhs.index, rhs.index); + } + + public: + // references can be created by copy-assignment only + IteratorValueRef(IteratorValueRef const& rhs) noexcept : soa(rhs.soa), index(rhs.index) { } + + // copy the content of a reference to the content of this one + IteratorValueRef& operator=(IteratorValueRef const& rhs); + + // move the content of a reference to the content of this one + IteratorValueRef& operator=(IteratorValueRef&& rhs) noexcept; + + // copy a value_type to the content of this reference + IteratorValueRef& operator=(IteratorValue const& rhs) { + return assign(rhs, std::make_index_sequence()); + } + + // move a value_type to the content of this reference + IteratorValueRef& operator=(IteratorValue&& rhs) noexcept { + return assign(rhs, std::make_index_sequence()); + } + + // access the elements of this reference (i.e. the "fields" of the structure) + template TypeAt const& get() const { return soa->elementAt(index); } + template TypeAt& get() { return soa->elementAt(index); } + }; + + + /* + * The value_type of iterator. This is basically the "structure" of the SoA. + * Internally we're using a tuple<> to store the data. + * This object is not trivial to construct, as it copies an entry of the SoA. + */ + class IteratorValue { + friend class IteratorValueRef; + friend iterator; + friend const_iterator; + using Type = std::tuple::type...>; + Type elements; + + template + static Type init(IteratorValueRef const& rhs, std::index_sequence) { + return Type{ rhs.soa->template elementAt(rhs.index)... }; + } + + template + static Type init(IteratorValueRef&& rhs, std::index_sequence) noexcept { + return Type{ std::move(rhs.soa->template elementAt(rhs.index))... }; + } + + public: + IteratorValue(IteratorValue const& rhs) = default; + IteratorValue(IteratorValue&& rhs) noexcept = default; + IteratorValue& operator=(IteratorValue const& rhs) = default; + IteratorValue& operator=(IteratorValue&& rhs) noexcept = default; + + // initialize and assign from a StructureRef + IteratorValue(IteratorValueRef const& rhs) + : elements(init(rhs, std::make_index_sequence())) {} + IteratorValue(IteratorValueRef&& rhs) noexcept + : elements(init(rhs, std::make_index_sequence())) {} + IteratorValue& operator=(IteratorValueRef const& rhs) { return operator=(IteratorValue(rhs)); } + IteratorValue& operator=(IteratorValueRef&& rhs) noexcept { return operator=(IteratorValue(rhs)); } + + // access the elements of this value_Type (i.e. the "fields" of the structure) + template TypeAt const& get() const { return std::get(elements); } + template TypeAt& get() { return std::get(elements); } + }; + + + /* + * An iterator to the SoA. This is only intended to be used with STL's algorithm, e.g.: sort(). + * Normally, SoA is not iterated globally, but rather an array at a time. + * Iterating itself is not too costly, as well as dereferencing by reference. However, + * dereferencing by value is. + */ + template + class Iterator { + friend class StructureOfArraysBase; + CVQualifiedSOAPointer soa; // don't use restrict, can have aliases if multiple iterators are created + size_t index; + + Iterator(CVQualifiedSOAPointer soa, size_t index) : soa(soa), index(index) {} + + public: + using value_type = IteratorValue; + using reference = IteratorValueRef; + using pointer = IteratorValueRef*; // FIXME: this should be a StructurePtr type + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + Iterator(Iterator const& rhs) noexcept = default; + Iterator& operator=(Iterator const& rhs) = default; + + reference operator*() const { return { soa, index }; } + reference operator*() { return { soa, index }; } + reference operator[](size_t n) { return *(*this + n); } + + template TypeAt const& get() const { return soa->template elementAt(index); } + template TypeAt& get() { return soa->template elementAt(index); } + + Iterator& operator++() { ++index; return *this; } + Iterator& operator--() { --index; return *this; } + Iterator& operator+=(size_t n) { index += n; return *this; } + Iterator& operator-=(size_t n) { index -= n; return *this; } + Iterator operator+(size_t n) const { return { soa, index + n }; } + Iterator operator-(size_t n) const { return { soa, index - n }; } + difference_type operator-(Iterator const& rhs) const { return index - rhs.index; } + bool operator==(Iterator const& rhs) const { return (index == rhs.index); } + bool operator!=(Iterator const& rhs) const { return (index != rhs.index); } + bool operator>=(Iterator const& rhs) const { return (index >= rhs.index); } + bool operator> (Iterator const& rhs) const { return (index > rhs.index); } + bool operator<=(Iterator const& rhs) const { return (index <= rhs.index); } + bool operator< (Iterator const& rhs) const { return (index < rhs.index); } + + // Postfix operator needed by Microsoft STL. + const Iterator operator++(int) { Iterator it(*this); index++; return it; } + const Iterator operator--(int) { Iterator it(*this); index--; return it; } + }; + + iterator begin() noexcept { return { this, 0u }; } + iterator end() noexcept { return { this, mSize }; } + const_iterator begin() const noexcept { return { this, 0u }; } + const_iterator end() const noexcept { return { this, mSize }; } + + // -------------------------------------------------------------------------------------------- + + StructureOfArraysBase() = default; + + explicit StructureOfArraysBase(size_t capacity) { + setCapacity(capacity); + } + + // not copyable for now + StructureOfArraysBase(StructureOfArraysBase const& rhs) = delete; + StructureOfArraysBase& operator=(StructureOfArraysBase const& rhs) = delete; + + // movability is trivial, so support it + StructureOfArraysBase(StructureOfArraysBase&& rhs) noexcept { + using std::swap; + swap(mCapacity, rhs.mCapacity); + swap(mSize, rhs.mSize); + swap(mArrays, rhs.mArrays); + swap(mAllocator, rhs.mAllocator); + } + + StructureOfArraysBase& operator=(StructureOfArraysBase&& rhs) noexcept { + if (this != &rhs) { + using std::swap; + swap(mCapacity, rhs.mCapacity); + swap(mSize, rhs.mSize); + swap(mArrays, rhs.mArrays); + swap(mAllocator, rhs.mAllocator); + } + return *this; + } + + ~StructureOfArraysBase() { + destroy_each(0, mSize); + mAllocator.free(std::get<0>(mArrays)); + } + + // -------------------------------------------------------------------------------------------- + + // return the size the array + size_t size() const noexcept { + return mSize; + } + + // return the capacity of the array + size_t capacity() const noexcept { + return mCapacity; + } + + // set the capacity of the array. the capacity cannot be smaller than the current size, + // the call is a no-op in that case. + UTILS_NOINLINE + void setCapacity(size_t capacity) { + // allocate enough space for "capacity" elements of each array + // capacity cannot change when optional storage is specified + if (capacity >= mSize) { + // TODO: not entirely sure if "max" of all alignments is always correct + constexpr size_t align = std::max({ std::max(alignof(std::max_align_t), alignof(Elements))... }); + const size_t sizeNeeded = getNeededSize(capacity); + void* buffer = mAllocator.alloc(sizeNeeded, align); + auto const oldBuffer = std::get<0>(mArrays); + + // move all the items (one array at a time) from the old allocation to the new + // this also update the array pointers + move_each(buffer, capacity); + + // free the old buffer + mAllocator.free(oldBuffer); + + // and make sure to update the capacity + mCapacity = capacity; + } + } + + void ensureCapacity(size_t needed) { + if (UTILS_UNLIKELY(needed > mCapacity)) { + // not enough space, increase the capacity + const size_t capacity = (needed * 3 + 1) / 2; + setCapacity(capacity); + } + } + + // grow or shrink the array to the given size. When growing, new elements are constructed + // with their default constructor. when shrinking, discarded elements are destroyed. + // If the arrays don't have enough capacity, the capacity is increased accordingly + // (the capacity is set to 3/2 of the asked size). + UTILS_NOINLINE + void resize(size_t needed) { + ensureCapacity(needed); + resizeNoCheck(needed); + if (needed <= mCapacity) { + // TODO: see if we should shrink the arrays + } + } + + void clear() noexcept { + resizeNoCheck(0); + } + + + inline void swap(size_t i, size_t j) noexcept { + forEach([i, j](auto p) { + using std::swap; + swap(p[i], p[j]); + }); + } + + // remove and destroy the last element of each array + inline void pop_back() noexcept { + if (mSize) { + destroy_each(mSize - 1, mSize); + mSize--; + } + } + + // create an element at the end of each array + StructureOfArraysBase& push_back() noexcept { + resize(mSize + 1); + return *this; + } + + StructureOfArraysBase& push_back(Structure&& args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(std::forward(args)); + } + + StructureOfArraysBase& push_back(Elements const& ... args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(args...); + } + + StructureOfArraysBase& push_back(Elements&& ... args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(std::forward(args)...); + } + + template + struct ElementIndices {}; + + template + struct BuildElementIndices : BuildElementIndices {}; + + template + struct BuildElementIndices<0, Indices...> : ElementIndices {}; + + template + void push_back_unsafe(Structure&& args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::get(args)}; + }() , ...); + } + + template + void push_back_unsafe(Elements const& ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{args}; + }() , ...); + } + + template + void push_back_unsafe(Elements && ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::forward(args)}; + }() , ...); + } + + StructureOfArraysBase& push_back_unsafe(Structure&& args) noexcept { + push_back_unsafe(std::forward(args), BuildElementIndices{}); + return *this; + } + + StructureOfArraysBase& push_back_unsafe(Elements const& ... args) noexcept { + push_back_unsafe(args..., BuildElementIndices{}); + + return *this; + } + + StructureOfArraysBase& push_back_unsafe(Elements&& ... args) noexcept { + push_back_unsafe(std::forward(args)..., BuildElementIndices{}); + return *this; + } + + template + void forEach(F&& f, ARGS&& ... args) { + for_each(mArrays, [&](size_t, auto* p) { + f(p, std::forward(args)...); + }); + } + + // return a pointer to the first element of the ElementIndex]th array + template + TypeAt* data() noexcept { + return std::get(mArrays); + } + + template + TypeAt const* data() const noexcept { + return std::get(mArrays); + } + + template + TypeAt* begin() noexcept { + return std::get(mArrays); + } + + template + TypeAt const* begin() const noexcept { + return std::get(mArrays); + } + + template + TypeAt* end() noexcept { + return std::get(mArrays) + size(); + } + + template + TypeAt const* end() const noexcept { + return std::get(mArrays) + size(); + } + + template + Slice> slice() noexcept { + return { begin(), end() }; + } + + template + Slice> slice() const noexcept { + return { begin(), end() }; + } + + // return a reference to the index'th element of the ElementIndex'th array + template + TypeAt& elementAt(size_t index) noexcept { + return data()[index]; + } + + template + TypeAt const& elementAt(size_t index) const noexcept { + return data()[index]; + } + + // return a reference to the last element of the ElementIndex'th array + template + TypeAt& back() noexcept { + return data()[size() - 1]; + } + + template + TypeAt const& back() const noexcept { + return data()[size() - 1]; + } + + template + struct Field { + SoA& soa; + IndexType i; + using Type = typename SoA::template TypeAt; + + UTILS_ALWAYS_INLINE Field& operator = (Field&& rhs) noexcept { + soa.elementAt(i) = soa.elementAt(rhs.i); + return *this; + } + + // auto-conversion to the field's type + UTILS_ALWAYS_INLINE operator Type&() noexcept { + return soa.elementAt(i); + } + UTILS_ALWAYS_INLINE operator Type const&() const noexcept { + return soa.elementAt(i); + } + // dereferencing the selected field + UTILS_ALWAYS_INLINE Type& operator ->() noexcept { + return soa.elementAt(i); + } + UTILS_ALWAYS_INLINE Type const& operator ->() const noexcept { + return soa.elementAt(i); + } + // address-of the selected field + UTILS_ALWAYS_INLINE Type* operator &() noexcept { + return &soa.elementAt(i); + } + UTILS_ALWAYS_INLINE Type const* operator &() const noexcept { + return &soa.elementAt(i); + } + // assignment to the field + UTILS_ALWAYS_INLINE Type const& operator = (Type const& other) noexcept { + return (soa.elementAt(i) = other); + } + UTILS_ALWAYS_INLINE Type const& operator = (Type&& other) noexcept { + return (soa.elementAt(i) = other); + } + // comparisons + UTILS_ALWAYS_INLINE bool operator==(Type const& other) const { + return (soa.elementAt(i) == other); + } + UTILS_ALWAYS_INLINE bool operator!=(Type const& other) const { + return (soa.elementAt(i) != other); + } + // calling the field + template + UTILS_ALWAYS_INLINE decltype(auto) operator()(ARGS&& ... args) noexcept { + return soa.elementAt(i)(std::forward(args)...); + } + template + UTILS_ALWAYS_INLINE decltype(auto) operator()(ARGS&& ... args) const noexcept { + return soa.elementAt(i)(std::forward(args)...); + } + }; + +private: + template + inline typename std::enable_if::type + for_each(std::tuple&, FuncT) {} + + template + inline typename std::enable_if::type + for_each(std::tuple& t, FuncT f) { + f(I, std::get(t)); + for_each(t, f); + } + + template + inline typename std::enable_if::type + for_each_index(std::tuple&, FuncT) {} + + template + inline typename std::enable_if::type + for_each_index(std::tuple& t, FuncT f) { + f.template operator()(std::get(t)); + for_each_index(t, f); + } + + inline void resizeNoCheck(size_t needed) noexcept { + assert_invariant(mCapacity >= needed); + if (needed < mSize) { + // we shrink the arrays + destroy_each(needed, mSize); + } else if (needed > mSize) { + // we grow the arrays + construct_each(mSize, needed); + } + // record the new size of the arrays + mSize = needed; + } + + // 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]; + } + + static inline std::array getOffsets(size_t capacity) noexcept { + // compute the required size of each array + const size_t sizes[] = { (sizeof(Elements) * capacity)... }; + + // we align each array to at least the same alignment guaranteed by malloc + constexpr size_t const alignments[] = { std::max(alignof(std::max_align_t), alignof(Elements))... }; + + // hopefully most of this gets unrolled and inlined + std::array offsets; + offsets[0] = 0; + UTILS_UNROLL + for (size_t i = 1; i < kArrayCount; i++) { + size_t unalignment = (offsets[i - 1] + sizes[i - 1]) % alignments[i]; + size_t alignment = unalignment ? (alignments[i] - unalignment) : 0; + offsets[i] = offsets[i - 1] + (sizes[i - 1] + alignment); + assert_invariant(offsets[i] % alignments[i] == 0); + } + return offsets; + } + + void construct_each(size_t from, size_t to) noexcept { + forEach([from, to](auto p) { + using T = typename std::decay::type; + // note: scalar types like int/float get initialized to zero + if constexpr (!std::is_trivially_default_constructible_v) { + for (size_t i = from; i < to; i++) { + new(p + i) T(); + } + } + }); + } + + void destroy_each(size_t from, size_t to) noexcept { + forEach([from, to](auto p) { + using T = typename std::decay::type; + if constexpr (!std::is_trivially_destructible_v) { + for (size_t i = from; i < to; i++) { + p[i].~T(); + } + } + }); + } + + void move_each(void* buffer, size_t capacity) noexcept { + auto offsets = getOffsets(capacity); + size_t index = 0; + if (mSize) { + auto size = mSize; // placate a compiler warning + forEach([buffer, &index, &offsets, size](auto p) { + using T = typename std::decay::type; + T* UTILS_RESTRICT b = static_cast(buffer); + + // go through each element and move them from the old array to the new + // then destroy them from the old array + T* UTILS_RESTRICT const arrayPointer = + reinterpret_cast(uintptr_t(b) + offsets[index]); + + // for trivial cases, just call memcpy() + if constexpr (std::is_trivially_copyable_v && + std::is_trivially_destructible_v) { + memcpy(arrayPointer, p, size * sizeof(T)); + } else { + for (size_t i = 0; i < size; i++) { + // we move an element by using the in-place move-constructor + new(arrayPointer + i) T(std::move(p[i])); + if constexpr (!std::is_trivially_destructible_v) { + // and delete them by calling the destructor directly + p[i].~T(); + } + } + } + index++; + }); + } + + // update the pointers + for_each(mArrays, [buffer, &offsets](size_t i, auto&& p) { + using Type = std::remove_reference_t; + p = Type((char*)buffer + offsets[i]); + }); + } + + // capacity in array elements + size_t mCapacity = 0; + // size in array elements + size_t mSize = 0; + // N pointers to each arrays + std::tuple...> mArrays{}; + Allocator mAllocator; +}; + + +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::operator=( + StructureOfArraysBase::IteratorValueRef const& rhs) { + return operator=(IteratorValue(rhs)); +} + +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::operator=( + StructureOfArraysBase::IteratorValueRef&& rhs) noexcept { + return operator=(IteratorValue(rhs)); +} + +template +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::assign( + StructureOfArraysBase::IteratorValue const& rhs, std::index_sequence) { + // implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue const& rhs) + auto UTILS_UNUSED l = { (soa->elementAt(index) = std::get(rhs.elements), 0)... }; + return *this; +} + +template +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::assign( + StructureOfArraysBase::IteratorValue&& rhs, std::index_sequence) noexcept { + // implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue&& rhs) noexcept + auto UTILS_UNUSED l = { + (soa->elementAt(index) = std::move(std::get(rhs.elements)), 0)... }; + return *this; +} + +template +using StructureOfArrays = StructureOfArraysBase, Elements ...>; + +} // namespace utils + +#endif // TNT_UTILS_STRUCTUREOFARRAYS_H + diff --git a/package/android/libs/filament/include/utils/algorithm.h b/package/android/libs/filament/include/utils/algorithm.h new file mode 100644 index 00000000..ea5ca44f --- /dev/null +++ b/package/android/libs/filament/include/utils/algorithm.h @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ALGORITHM_H +#define TNT_UTILS_ALGORITHM_H + +#include + +#include // for std::enable_if + +#include +#include + +namespace utils { + +namespace details { + +template +constexpr inline T popcount(T v) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::popcount() only support up to 128 bits"); + constexpr T ONES = ~T(0); + v = v - ((v >> 1u) & ONES / 3); + v = (v & ONES / 15 * 3) + ((v >> 2u) & ONES / 15 * 3); + v = (v + (v >> 4u)) & ONES / 255 * 15; + return (T) (v * (ONES / 255)) >> (sizeof(T) - 1) * CHAR_BIT; +} + +template::value>> +constexpr inline T clz(T x) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::clz() only support up to 128 bits"); + x |= (x >> 1u); + x |= (x >> 2u); + x |= (x >> 4u); + x |= (x >> 8u); + x |= (x >> 16u); + if constexpr (sizeof(T) * CHAR_BIT >= 64) { // just to silence compiler warning + x |= (x >> 32u); + } + if constexpr (sizeof(T) * CHAR_BIT >= 128) { // just to silence compiler warning + x |= (x >> 64u); + } + return T(sizeof(T) * CHAR_BIT) - details::popcount(x); +} + +template::value>> +constexpr inline T ctz(T x) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 64, "details::ctz() only support up to 64 bits"); + T c = sizeof(T) * CHAR_BIT; +#if defined(_MSC_VER) + // equivalent to x & -x, but MSVC yield a warning for using unary minus operator on unsigned types + x &= (~x + 1); +#else + // equivalent to x & (~x + 1), but some compilers generate a better sequence on ARM + x &= -x; +#endif + if (x) c--; + if (sizeof(T) * CHAR_BIT >= 64) { + if (x & T(0x00000000FFFFFFFF)) c -= 32; + } + if (x & T(0x0000FFFF0000FFFF)) c -= 16; + if (x & T(0x00FF00FF00FF00FF)) c -= 8; + if (x & T(0x0F0F0F0F0F0F0F0F)) c -= 4; + if (x & T(0x3333333333333333)) c -= 2; + if (x & T(0x5555555555555555)) c -= 1; + return c; +} + +} // namespace details + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE clz(unsigned int x) noexcept { +#if __has_builtin(__builtin_clz) + return __builtin_clz(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE clz(unsigned long x) noexcept { +#if __has_builtin(__builtin_clzl) + return __builtin_clzl(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE clz(unsigned long long x) noexcept { +#if __has_builtin(__builtin_clzll) + return __builtin_clzll(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE ctz(unsigned int x) noexcept { +#if __has_builtin(__builtin_ctz) + return __builtin_ctz(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE ctz(unsigned long x) noexcept { +#if __has_builtin(__builtin_ctzl) + return __builtin_ctzl(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE ctz(unsigned long long x) noexcept { +#if __has_builtin(__builtin_ctzll) + return __builtin_ctzll(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE popcount(unsigned int x) noexcept { +#if __has_builtin(__builtin_popcount) + return __builtin_popcount(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE popcount(unsigned long x) noexcept { +#if __has_builtin(__builtin_popcountl) + return __builtin_popcountl(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE popcount(unsigned long long x) noexcept { +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +uint8_t UTILS_ALWAYS_INLINE popcount(uint8_t x) noexcept { + return (uint8_t)popcount((unsigned int)x); +} + +template::value && std::is_unsigned::value>> +constexpr inline UTILS_PUBLIC UTILS_PURE +T log2i(T x) noexcept { + return (sizeof(x) * 8 - 1u) - clz(x); +} + +template +inline UTILS_PUBLIC +RandomAccessIterator partition_point( + RandomAccessIterator first, RandomAccessIterator last, COMPARE pred, + bool assume_power_of_two = false) { + size_t len = last - first; + + if (!assume_power_of_two) { + // handle non power-of-two sized arrays. If it's POT, the next line is a no-op + // and gets optimized out if the size is known at compile time. + len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2 + size_t difference = (last - first) - len; + first += !difference || pred(first[len]) ? difference : 0; + } + + while (len) { + // The number of repetitions here doesn't affect the result. We manually unroll the loop + // twice, to guarantee we have at least two iterations without branches (for the case + // where the size is not known at compile time + first += pred(first[len>>=1u]) ? len : 0; + first += pred(first[len>>=1u]) ? len : 0; + } + first += pred(*first); + return first; +} + +template +#if __has_builtin(__builtin_bit_cast) +constexpr +#else +inline +#endif +Dest bit_cast(const Source& source) noexcept { +#if __has_builtin(__builtin_bit_cast) + return __builtin_bit_cast(Dest, source); +#else + static_assert(sizeof(Dest) == sizeof(Source), + "bit_cast requires source and destination to be the same size"); + static_assert(std::is_trivially_copyable_v, + "bit_cast requires the destination type to be copyable"); + static_assert(std::is_trivially_copyable_v, + "bit_cast requires the source type to be copyable"); + Dest dest; + memcpy(&dest, &source, sizeof(dest)); + return dest; +#endif +} + +} // namespace utils + +#endif // TNT_UTILS_ALGORITHM_H diff --git a/package/android/libs/filament/include/utils/bitset.h b/package/android/libs/filament/include/utils/bitset.h new file mode 100644 index 00000000..281e5dfc --- /dev/null +++ b/package/android/libs/filament/include/utils/bitset.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_BITSET_H +#define TNT_UTILS_BITSET_H + +#include +#include +#include + +#include +#include +#include + +#include // for std::fill +#include +#include + +#if defined(__ARM_NEON) +# if defined(__ARM_ACLE) && defined(__aarch64__) +# include +# define TNT_UTILS_BITSET_USE_NEON 1 +# endif +#endif + +namespace utils { + +/* + * This bitset<> class is different from std::bitset<> in that it allows us to control + * the exact storage size. This is useful for small bitset (e.g. < 64, on 64-bits machines). + * It also allows for lexicographical compares (i.e. sorting). + */ + +template::value && + std::is_unsigned::value>::type> +class UTILS_PUBLIC bitset { + T storage[N]; + +public: + static constexpr T BITS_PER_WORD = sizeof(T) * 8; + static constexpr T BIT_COUNT = BITS_PER_WORD * N; + static constexpr T WORLD_COUNT = N; + using container_type = T; + + bitset() noexcept { + std::fill(std::begin(storage), std::end(storage), 0); + } + + T getBitsAt(size_t n) const noexcept { + assert_invariant(n + void forEachSetBit(F exec) const noexcept { + for (size_t i = 0; i < N; i++) { + T v = storage[i]; + while (v) { + T k = utils::ctz(v); + v &= ~(T(1) << k); + exec(size_t(k + BITS_PER_WORD * i)); + } + } + } + + size_t size() const noexcept { return N * BITS_PER_WORD; } + + bool test(size_t bit) const noexcept { return operator[](bit); } + + void set(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] |= T(1) << (b % BITS_PER_WORD); + } + + void set(size_t b, bool value) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] &= ~(T(1) << (b % BITS_PER_WORD)); + storage[b / BITS_PER_WORD] |= T(value) << (b % BITS_PER_WORD); + } + + void unset(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] &= ~(T(1) << (b % BITS_PER_WORD)); + } + + void flip(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] ^= T(1) << (b % BITS_PER_WORD); + } + + + void reset() noexcept { + std::fill(std::begin(storage), std::end(storage), 0); + } + + bool operator[](size_t b) const noexcept { + assert_invariant(b / BITS_PER_WORD < N); + return bool(storage[b / BITS_PER_WORD] & (T(1) << (b % BITS_PER_WORD))); + } + + size_t count() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0 && BIT_COUNT / 128 < 31) { + // Use NEON for bitset multiple of 128 bits. + // The intermediate computation can't handle more than 31*128 bits because + // intermediate counts must be 8 bits. + uint8x16_t const* const p = (uint8x16_t const*) storage; + uint8x16_t counts = vcntq_u8(p[0]); + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + counts += vcntq_u8(p[i]); + } + return vaddlvq_u8(counts); + } else +#endif + { + T r = utils::popcount(storage[0]); + for (size_t i = 1; i < N; ++i) { + r += utils::popcount(storage[i]); + } + return r; + } + } + + bool any() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint64x2_t const* const p = (uint64x2_t const*) storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r |= p[i]; + } + return bool(r[0] | r[1]); + } else +#endif + { + T r = storage[0]; + for (size_t i = 1; i < N; ++i) { + r |= storage[i]; + } + return bool(r); + } + } + + bool none() const noexcept { + return !any(); + } + + bool all() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint64x2_t const* const p = (uint64x2_t const*) storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r &= p[i]; + } + return T(~(r[0] & r[1])) == T(0); + } else +#endif + { + T r = storage[0]; + for (size_t i = 1; i < N; ++i) { + r &= storage[i]; + } + return T(~r) == T(0); + } + } + + bool operator!=(const bitset& b) const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + bitset temp(*this ^ b); + uint64x2_t const* const p = (uint64x2_t const*) temp.storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r |= p[i]; + } + return bool(r[0] | r[1]); + } else +#endif + { + T r = storage[0] ^ b.storage[0]; + for (size_t i = 1; i < N; ++i) { + r |= storage[i] ^ b.storage[i]; + } + return bool(r); + } + } + + bool operator==(const bitset& b) const noexcept { + return !operator!=(b); + } + + bitset& operator&=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] &= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] &= b.storage[i]; + } + } + return *this; + } + + bitset& operator|=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] |= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] |= b.storage[i]; + } + } + return *this; + } + + bitset& operator^=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] ^= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] ^= b.storage[i]; + } + } + return *this; + } + + bitset operator~() const noexcept { + bitset r; +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) r.storage; + uint8x16_t const* const q = (uint8x16_t const*) storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] = ~q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + r.storage[i] = ~storage[i]; + } + } + return r; + } + +private: + friend bool operator<(bitset const& lhs, bitset const& rhs) noexcept { + return std::lexicographical_compare( + std::begin(lhs.storage), std::end(lhs.storage), + std::begin(rhs.storage), std::end(rhs.storage) + ); + } + + friend bitset operator&(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) &= rhs; + } + + friend bitset operator|(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) |= rhs; + } + + friend bitset operator^(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) ^= rhs; + } +}; + +using bitset8 = bitset; +using bitset32 = bitset; +using bitset64 = bitset; +using bitset128 = bitset; +using bitset256 = bitset; + +static_assert(sizeof(bitset8) == 1, "bitset8 isn't 8 bits!"); +static_assert(sizeof(bitset32) == 4, "bitset32 isn't 32 bits!"); +static_assert(sizeof(bitset64) == 8, "bitset64 isn't 64 bits!"); +static_assert(sizeof(bitset128) == 16, "bitset128 isn't 128 bits!"); +static_assert(sizeof(bitset256) == 32, "bitset256 isn't 256 bits!"); + +} // namespace utils + +#endif // TNT_UTILS_BITSET_H diff --git a/package/android/libs/filament/include/utils/compiler.h b/package/android/libs/filament/include/utils/compiler.h new file mode 100644 index 00000000..710c901e --- /dev/null +++ b/package/android/libs/filament/include/utils/compiler.h @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_COMPILER_H +#define TNT_UTILS_COMPILER_H + +// compatibility with non-clang compilers... +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_attribute(visibility) +# define UTILS_PUBLIC __attribute__((visibility("default"))) +#else +# define UTILS_PUBLIC +#endif + +#if __has_attribute(deprecated) +# define UTILS_DEPRECATED [[deprecated]] +#else +# define UTILS_DEPRECATED +#endif + +#if __has_attribute(packed) +# define UTILS_PACKED __attribute__((packed)) +#else +# define UTILS_PACKED +#endif + +#if __has_attribute(noreturn) +# define UTILS_NORETURN __attribute__((noreturn)) +#else +# define UTILS_NORETURN +#endif + +#if __has_attribute(fallthrough) +# define UTILS_FALLTHROUGH [[fallthrough]] +#else +# define UTILS_FALLTHROUGH +#endif + +#if __has_attribute(visibility) +# ifndef TNT_DEV +# define UTILS_PRIVATE __attribute__((visibility("hidden"))) +# else +# define UTILS_PRIVATE +# endif +#else +# define UTILS_PRIVATE +#endif + +#define UTILS_NO_SANITIZE_THREAD +#if __has_feature(thread_sanitizer) +#undef UTILS_NO_SANITIZE_THREAD +#define UTILS_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread"))) +#endif + +#define UTILS_HAS_SANITIZE_THREAD 0 +#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#undef UTILS_HAS_SANITIZE_THREAD +#define UTILS_HAS_SANITIZE_THREAD 1 +#endif + +#define UTILS_HAS_SANITIZE_MEMORY 0 +#if __has_feature(memory_sanitizer) +#undef UTILS_HAS_SANITIZE_MEMORY +#define UTILS_HAS_SANITIZE_MEMORY 1 +#endif + +/* + * helps the compiler's optimizer predicting branches + */ +#if __has_builtin(__builtin_expect) +# ifdef __cplusplus +# define UTILS_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define UTILS_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +# else +# define UTILS_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define UTILS_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +# endif +#else +# define UTILS_LIKELY( exp ) (!!(exp)) +# define UTILS_UNLIKELY( exp ) (!!(exp)) +#endif + +#if __has_builtin(__builtin_prefetch) +# define UTILS_PREFETCH( exp ) (__builtin_prefetch(exp)) +#else +# define UTILS_PREFETCH( exp ) +#endif + +#if __has_builtin(__builtin_assume) +# define UTILS_ASSUME( exp ) (__builtin_assume(exp)) +#else +# define UTILS_ASSUME( exp ) +#endif + +#if (defined(__i386__) || defined(__x86_64__)) +# define UTILS_HAS_HYPER_THREADING 1 // on x86 we assume we have hyper-threading. +#else +# define UTILS_HAS_HYPER_THREADING 0 +#endif + +#if defined(FILAMENT_SINGLE_THREADED) +# define UTILS_HAS_THREADING 0 +#elif defined(__EMSCRIPTEN__) +# if defined(__EMSCRIPTEN_PTHREADS__) && defined(FILAMENT_WASM_THREADS) +# define UTILS_HAS_THREADING 1 +# else +# define UTILS_HAS_THREADING 0 +# endif +#else +# define UTILS_HAS_THREADING 1 +#endif + +#if __has_attribute(noinline) +#define UTILS_NOINLINE __attribute__((noinline)) +#else +#define UTILS_NOINLINE +#endif + +#if __has_attribute(always_inline) +#define UTILS_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define UTILS_ALWAYS_INLINE +#endif + +#if __has_attribute(pure) +#define UTILS_PURE __attribute__((pure)) +#else +#define UTILS_PURE +#endif + +#if __has_attribute(maybe_unused) || (defined(_MSC_VER) && _MSC_VER >= 1911) +#define UTILS_UNUSED [[maybe_unused]] +#define UTILS_UNUSED_IN_RELEASE [[maybe_unused]] +#elif __has_attribute(unused) +#define UTILS_UNUSED __attribute__((unused)) +#define UTILS_UNUSED_IN_RELEASE __attribute__((unused)) +#else +#define UTILS_UNUSED +#define UTILS_UNUSED_IN_RELEASE +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define UTILS_RESTRICT __restrict +#elif (defined(__clang__) || defined(__GNUC__)) +# define UTILS_RESTRICT __restrict__ +#else +# define UTILS_RESTRICT +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 1 +#elif __has_feature(cxx_thread_local) +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 1 +#else +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 0 +#endif + +#if defined(__clang__) +#define UTILS_NONNULL _Nonnull +#define UTILS_NULLABLE _Nullable +#else +#define UTILS_NONNULL +#define UTILS_NULLABLE +#endif + +#if defined(_MSC_VER) +// MSVC does not support loop unrolling hints +# define UTILS_UNROLL +# define UTILS_NOUNROLL +#else +// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax. +# define UTILS_UNROLL _Pragma("unroll") +# define UTILS_NOUNROLL _Pragma("nounroll") +#endif + +#if __has_feature(cxx_rtti) || defined(_CPPRTTI) +# define UTILS_HAS_RTTI 1 +#else +# define UTILS_HAS_RTTI 0 +#endif + +#ifdef __ARM_ACLE +# include +# define UTILS_WAIT_FOR_INTERRUPT() __wfi() +# define UTILS_WAIT_FOR_EVENT() __wfe() +# define UTILS_BROADCAST_EVENT() __sev() +# define UTILS_SIGNAL_EVENT() __sevl() +# define UTILS_PAUSE() __yield() +# define UTILS_PREFETCHW(addr) __pldx(1, 0, 0, addr) +#else // !__ARM_ACLE +# if (defined(__i386__) || defined(__x86_64__)) +# define UTILS_X86_PAUSE {__asm__ __volatile__( "rep; nop" : : : "memory" );} +# define UTILS_WAIT_FOR_INTERRUPT() UTILS_X86_PAUSE +# define UTILS_WAIT_FOR_EVENT() UTILS_X86_PAUSE +# define UTILS_BROADCAST_EVENT() +# define UTILS_SIGNAL_EVENT() +# define UTILS_PAUSE() UTILS_X86_PAUSE +# define UTILS_PREFETCHW(addr) UTILS_PREFETCH(addr) +# else // !x86 +# define UTILS_WAIT_FOR_INTERRUPT() +# define UTILS_WAIT_FOR_EVENT() +# define UTILS_BROADCAST_EVENT() +# define UTILS_SIGNAL_EVENT() +# define UTILS_PAUSE() +# define UTILS_PREFETCHW(addr) UTILS_PREFETCH(addr) +# endif // x86 +#endif // __ARM_ACLE + + +// ssize_t is a POSIX type. +#if defined(WIN32) || defined(_WIN32) +#include +typedef SSIZE_T ssize_t; +#endif + +#ifdef _MSC_VER +# define UTILS_EMPTY_BASES __declspec(empty_bases) +#else +# define UTILS_EMPTY_BASES +#endif + +#if defined(WIN32) || defined(_WIN32) + #define IMPORTSYMB __declspec(dllimport) +#else + #define IMPORTSYMB +#endif + +#if defined(_MSC_VER) && !defined(__PRETTY_FUNCTION__) +# define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + + +#if defined(_MSC_VER) +# define UTILS_WARNING_PUSH _Pragma("warning( push )") +# define UTILS_WARNING_POP _Pragma("warning( pop )") +# define UTILS_WARNING_ENABLE_PADDED _Pragma("warning(1: 4324)") +#elif defined(__clang__) +# define UTILS_WARNING_PUSH _Pragma("clang diagnostic push") +# define UTILS_WARNING_POP _Pragma("clang diagnostic pop") +# define UTILS_WARNING_ENABLE_PADDED _Pragma("clang diagnostic warning \"-Wpadded\"") +#else +# define UTILS_WARNING_PUSH +# define UTILS_WARNING_POP +# define UTILS_WARNING_ENABLE_PADDED +#endif + +#endif // TNT_UTILS_COMPILER_H diff --git a/package/android/libs/filament/include/utils/compressed_pair.h b/package/android/libs/filament/include/utils/compressed_pair.h new file mode 100644 index 00000000..62bf2de4 --- /dev/null +++ b/package/android/libs/filament/include/utils/compressed_pair.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_COMPRESSED_PAIR_H +#define TNT_UTILS_COMPRESSED_PAIR_H + +#include +#include + +namespace utils { + +template +struct dependent_type : public T { +}; + +template, bool> = true> +struct compressed_pair : private T1, private T2 { + + template, Dummy>::value && + dependent_type, Dummy>::value>> + compressed_pair() : T1(), T2() {} + + template + compressed_pair(U1&& other1, U2&& other2) + : T1(std::forward(other1)), + T2(std::forward(other2)) {} + + T1& first() noexcept { + return static_cast(*this); + } + + T2& second() noexcept { + return static_cast(*this); + } + + T1 const& first() const noexcept { + return static_cast(*this); + } + + T2 const& second() const noexcept { + return static_cast(*this); + } + + void swap(compressed_pair& other) noexcept { + using std::swap; + swap(first(), other.first()); + swap(second(), other.second()); + } +}; + +} // namespace utils + +#endif // TNT_UTILS_COMPRESSED_PAIR_H diff --git a/package/android/libs/filament/include/utils/debug.h b/package/android/libs/filament/include/utils/debug.h new file mode 100644 index 00000000..4c118725 --- /dev/null +++ b/package/android/libs/filament/include/utils/debug.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_DEBUG_H +#define TNT_UTILS_DEBUG_H + +#include + +namespace utils { +void panic(const char *func, const char * file, int line, const char *assertion) noexcept; +} // namespace filament + +#ifdef NDEBUG +# define assert_invariant(e) ((void)0) +#else +# define assert_invariant(e) \ + (UTILS_LIKELY(e) ? ((void)0) : utils::panic(__func__, __FILE__, __LINE__, #e)) +#endif // NDEBUG + +#endif // TNT_UTILS_DEBUG_H diff --git a/package/android/libs/filament/include/utils/linux/Mutex.h b/package/android/libs/filament/include/utils/linux/Mutex.h new file mode 100644 index 00000000..f548d53e --- /dev/null +++ b/package/android/libs/filament/include/utils/linux/Mutex.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_UTILS_LINUX_MUTEX_H +#define TNT_UTILS_LINUX_MUTEX_H + +#include + +#include + +#include + +namespace utils { + +/* + * A very simple mutex class that can be used as an (almost) drop-in replacement + * for std::mutex. + * It is very low overhead as most of it is inlined. + */ + +class Mutex { +public: + constexpr Mutex() noexcept = default; + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void lock() noexcept { + uint32_t old_state = UNLOCKED; + if (UTILS_UNLIKELY(!mState.compare_exchange_strong(old_state, + LOCKED, std::memory_order_acquire, std::memory_order_relaxed))) { + wait(); + } + } + + void unlock() noexcept { + if (UTILS_UNLIKELY(mState.exchange(UNLOCKED, std::memory_order_release) == LOCKED_CONTENDED)) { + wake(); + } + } + +private: + enum { + UNLOCKED = 0, LOCKED = 1, LOCKED_CONTENDED = 2 + }; + std::atomic mState = { UNLOCKED }; + + void wait() noexcept; + void wake() noexcept; +}; + +} // namespace utils + +#endif // TNT_UTILS_LINUX_MUTEX_H diff --git a/package/android/libs/filament/include/utils/memalign.h b/package/android/libs/filament/include/utils/memalign.h new file mode 100644 index 00000000..4c048bff --- /dev/null +++ b/package/android/libs/filament/include/utils/memalign.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_UTILS_MEMALIGN_H +#define TNT_UTILS_MEMALIGN_H + +#include + +#include +#include +#include + +#if defined(WIN32) +#include +#endif + +namespace utils { + +inline void* aligned_alloc(size_t size, size_t align) noexcept { + // 'align' must be a power of two and a multiple of sizeof(void*) + align = (align < sizeof(void*)) ? sizeof(void*) : align; + assert(align && !(align & align - 1)); + assert((align % sizeof(void*)) == 0); + + void* p = nullptr; + +#if defined(WIN32) + p = ::_aligned_malloc(size, align); +#else + ::posix_memalign(&p, align, size); +#endif + return p; +} + +inline void aligned_free(void* p) noexcept { +#if defined(WIN32) + ::_aligned_free(p); +#else + ::free(p); +#endif +} + +/* + * This allocator can be used with std::vector for instance to ensure all items are aligned + * to their alignof(). e.g. + * + * template + * using aligned_vector = std::vector>; + * + * aligned_vector foos; + * + */ +template +class STLAlignedAllocator { + static_assert(!(alignof(TYPE) & (alignof(TYPE) - 1)), "alignof(T) must be a power of two"); + +public: + using value_type = TYPE; + using pointer = TYPE*; + using const_pointer = const TYPE*; + using reference = TYPE&; + using const_reference = const TYPE&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + template + struct rebind { using other = STLAlignedAllocator; }; + + inline STLAlignedAllocator() noexcept = default; + + template + inline explicit STLAlignedAllocator(const STLAlignedAllocator&) noexcept {} + + inline ~STLAlignedAllocator() noexcept = default; + + inline pointer allocate(size_type n) noexcept { + return (pointer)aligned_alloc(n * sizeof(value_type), alignof(TYPE)); + } + + inline void deallocate(pointer p, size_type) { + aligned_free(p); + } + + // stateless allocators are always equal + template + bool operator==(const STLAlignedAllocator&) const noexcept { + return true; + } + + template + bool operator!=(const STLAlignedAllocator&) const noexcept { + return false; + } +}; + +} // namespace utils + +#endif // TNT_UTILS_MEMALIGN_H diff --git a/package/android/libs/filament/include/utils/ostream.h b/package/android/libs/filament/include/utils/ostream.h new file mode 100644 index 00000000..623cf9c0 --- /dev/null +++ b/package/android/libs/filament/include/utils/ostream.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_UTILS_OSTREAM_H +#define TNT_UTILS_OSTREAM_H + +#include +#include +#include + +#include +#include +#include + +namespace utils::io { + +struct ostream_; + +class UTILS_PUBLIC ostream : protected utils::PrivateImplementation { + friend struct ostream_; + +public: + virtual ~ostream(); + + ostream& operator<<(short value) noexcept; + ostream& operator<<(unsigned short value) noexcept; + + ostream& operator<<(char value) noexcept; + ostream& operator<<(unsigned char value) noexcept; + + ostream& operator<<(int value) noexcept; + ostream& operator<<(unsigned int value) noexcept; + + ostream& operator<<(long value) noexcept; + ostream& operator<<(unsigned long value) noexcept; + + ostream& operator<<(long long value) noexcept; + ostream& operator<<(unsigned long long value) noexcept; + + ostream& operator<<(float value) noexcept; + ostream& operator<<(double value) noexcept; + ostream& operator<<(long double value) noexcept; + + ostream& operator<<(bool value) noexcept; + + ostream& operator<<(const void* value) noexcept; + + ostream& operator<<(const char* string) noexcept; + ostream& operator<<(const unsigned char* string) noexcept; + + ostream& operator<<(std::string const& s) noexcept; + ostream& operator<<(std::string_view const& s) noexcept; + + ostream& operator<<(ostream& (* f)(ostream&)) noexcept { return f(*this); } + + ostream& dec() noexcept; + ostream& hex() noexcept; + + /*! @cond PRIVATE */ + // Sets a consumer of the log. The consumer is invoked on flush() and replaces the default. + // Thread safe and reentrant. + using ConsumerCallback = void(*)(void*, char const*); + void setConsumer(ConsumerCallback consumer, void* user) noexcept; + /*! @endcond */ + +protected: + ostream& print(const char* format, ...) noexcept; + + class Buffer { + public: + Buffer() noexcept; + ~Buffer() noexcept; + + Buffer(const Buffer&) = delete; + Buffer& operator=(const Buffer&) = delete; + + const char* get() const noexcept { return buffer; } + + std::pair grow(size_t s) noexcept; + void advance(ssize_t n) noexcept; + void reset() noexcept; + + private: + void reserve(size_t newSize) noexcept; + + char* buffer = nullptr; // buffer address + char* curr = nullptr; // current pointer + size_t size = 0; // size remaining + size_t capacity = 0; // total capacity of the buffer + }; + + Buffer& getBuffer() noexcept; + Buffer const& getBuffer() const noexcept; + +private: + virtual ostream& flush() noexcept = 0; + + friend ostream& hex(ostream& s) noexcept; + friend ostream& dec(ostream& s) noexcept; + friend ostream& endl(ostream& s) noexcept; + UTILS_PUBLIC friend ostream& flush(ostream& s) noexcept; + + enum type { + SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, FLOAT, DOUBLE, + LONG_DOUBLE + }; + + const char* getFormat(type t) const noexcept; +}; + +// handles utils::bitset +inline ostream& operator << (ostream& o, utils::bitset32 const& s) noexcept { + return o << (void*)uintptr_t(s.getValue()); +} + +// handles vectors from libmath (but we do this generically, without needing a dependency on libmath) +template class VECTOR, typename T> +inline ostream& operator<<(ostream& stream, const VECTOR& v) { + stream << "< "; + for (size_t i = 0; i < v.size() - 1; i++) { + stream << v[i] << ", "; + } + stream << v[v.size() - 1] << " >"; + return stream; +} + +inline ostream& hex(ostream& s) noexcept { return s.hex(); } +inline ostream& dec(ostream& s) noexcept { return s.dec(); } +inline ostream& endl(ostream& s) noexcept { return flush(s << '\n'); } + +} // namespace utils::io + +#endif // TNT_UTILS_OSTREAM_H diff --git a/package/android/libs/filament/include/utils/unwindows.h b/package/android/libs/filament/include/utils/unwindows.h new file mode 100644 index 00000000..328ba4dd --- /dev/null +++ b/package/android/libs/filament/include/utils/unwindows.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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. + */ + +#if defined (WIN32) + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#ifdef far +#undef far +#endif + +#ifdef near +#undef near +#endif + +#ifdef ERROR +#undef ERROR +#endif + +#ifdef OPAQUE +#undef OPAQUE +#endif + +#ifdef TRANSPARENT +#undef TRANSPARENT +#endif + +#ifdef PURE +#undef PURE +#endif + +#endif diff --git a/package/android/libs/filament/include/viewer/AutomationEngine.h b/package/android/libs/filament/include/viewer/AutomationEngine.h new file mode 100644 index 00000000..8747f59d --- /dev/null +++ b/package/android/libs/filament/include/viewer/AutomationEngine.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_AUTOMATION_ENGINE_H +#define VIEWER_AUTOMATION_ENGINE_H + +#include + +namespace filament { + +class ColorGrading; +class Engine; +class LightManager; +class MaterialInstance; +class Renderer; +class View; + +namespace viewer { + +/** + * The AutomationEngine makes it easy to push a bag of settings values to Filament. + * It can also be used to iterate through settings permutations for testing purposes. + * + * When creating an automation engine for testing purposes, clients give it an immutable reference + * to an AutomationSpec. It is always in one of two states: running or idle. The running state can + * be entered immediately (startRunning) or by requesting batch mode (startBatchMode). + * + * When executing a test, clients should call tick() after each frame is rendered, which gives + * automation an opportunity to push settings to Filament, increment the current test index (if + * enough time has elapsed), and request an asynchronous screenshot. + * + * The time to sleep between tests is configurable and can be set to zero. Automation also waits a + * specified minimum number of frames between tests. + * + * Batch mode is meant for non-interactive applications. In batch mode, automation defers applying + * the first test case until the client unblocks it via signalBatchMode(). This is useful when + * waiting for a large model file to become fully loaded. Batch mode also offers a query + * (shouldClose) that is triggered after the last test has been invoked. + */ +class UTILS_PUBLIC AutomationEngine { +public: + /** + * Allows users to toggle screenshots, change the sleep duration between tests, etc. + */ + struct Options { + /** + * Minimum time that automation waits between applying a settings object and advancing + * to the next test case. Specified in seconds. + */ + float sleepDuration = 0.2f; + + /** + * Similar to sleepDuration, but expressed as a frame count. Both the minimum sleep time + * and the minimum frame count must be elapsed before automation advances to the next test. + */ + int minFrameCount = 2; + + /** + * If true, test progress is dumped to the utils Log (info priority). + */ + bool verbose = true; + + /** + * If true, the tick function writes out a screenshot before advancing to the next test. + */ + bool exportScreenshots = false; + + /** + * If true, the tick function writes out a settings JSON file before advancing. + */ + bool exportSettings = false; + }; + + /** + * Collection of Filament objects that can be modified by the automation engine. + */ + struct ViewerContent { + View* view; + Renderer* renderer; + MaterialInstance* const* materials; + size_t materialCount; + LightManager* lightManager; + Scene* scene; + IndirectLight* indirectLight; + utils::Entity sunlight; + utils::Entity* assetLights; + size_t assetLightCount; + }; + + /** + * Creates an automation engine and places it in an idle state. + * + * @param spec Specifies a set of settings permutations (owned by the client). + * @param settings Client-owned settings object. This not only supplies the initial + * state, it also receives changes during tick(). This is useful when + * building automation into an application that has a settings UI. + * + * @see setOptions + * @see startRunning + */ + AutomationEngine(const AutomationSpec* spec, Settings* settings) : + mSpec(spec), mSettings(settings) {} + + /** + * Shortcut constructor that creates an automation engine from a JSON string. + * + * This constructor can be used if the user does not need to monitor how the settings + * change over time and does not need ownership over the AutomationSpec. + * + * An example of a JSON spec can be found by searching the repo for DEFAULT_AUTOMATION. + * This is documented using a JSON schema (look for viewer/schemas/automation.json). + * + * @param jsonSpec Valid JSON string that conforms to the automation schema. + * @param size Number of characters in the JSON string. + * @return Automation engine or null if unable to read the JSON. + */ + static AutomationEngine* createFromJSON(const char* jsonSpec, size_t size); + + /** + * Creates an automation engine for the sole purpose of pushing settings, or for executing + * the default test sequence. + * + * To see how the default test sequence is generated, search for DEFAULT_AUTOMATION. + */ + static AutomationEngine* createDefault(); + + /** + * Activates the automation test. During the subsequent call to tick(), the first test is + * applied and automation enters the running state. + */ + void startRunning(); + + /** + * Activates the automation test, but enters a paused state until the user calls + * signalBatchMode(). + */ + void startBatchMode(); + + /** + * Notifies the automation engine that time has passed, a new frame has been rendered. + * + * This is when settings get applied, screenshots are (optionally) exported, and the internal + * test counter is potentially incremented. + * + * @param content Contains the Filament View, Materials, and Renderer that get modified. + * @param deltaTime The amount of time that has passed since the previous tick in seconds. + */ + void tick(Engine* engine, const ViewerContent& content, float deltaTime); + + /** + * Mutates a set of client-owned Filament objects according to a JSON string. + * + * This method is an alternative to tick(). It allows clients to use the automation engine as a + * remote control, as opposed to iterating through a predetermined test sequence. + * + * This updates the stashed Settings object, then pushes those settings to the given + * Filament objects. Clients can optionally call getColorGrading() after calling this method. + * + * @param json Contains the JSON string with a set of changes that need to be pushed. + * @param jsonLength Number of characters in the json string. + * @param content Contains a set of Filament objects that you want to mutate. + */ + void applySettings(Engine* engine, const char* json, size_t jsonLength, const ViewerContent& content); + + /** + * Gets a color grading object that corresponds to the latest settings. + * + * This method either returns a cached instance, or it destroys the cached instance and creates + * a new one. + */ + ColorGrading* getColorGrading(Engine* engine); + + /** + * Gets the current viewer options. + * + * NOTE: Focal length here might be different from the user-specified value, due to DoF options. + */ + ViewerOptions getViewerOptions() const; + + /** + * Signals that batch mode can begin. Call this after all meshes and textures finish loading. + */ + void signalBatchMode() { mBatchModeAllowed = true; } + + /** + * Cancels an in-progress automation session. + */ + void stopRunning() { mIsRunning = false; } + + /** + * Signals that the application is closing, so all pending screenshots should be cancelled. + */ + void terminate(); + + /** + * Configures the automation engine for users who wish to set up a custom sleep time + * between tests, etc. + */ + void setOptions(Options options) { mOptions = options; } + + /** + * Returns true if automation is in batch mode and all tests have finished. + */ + bool shouldClose() const { return mShouldClose; } + + /** + * Convenience function that writes out a JSON file to disk containing all settings. + * + * @param Settings State vector to serialize. + * @param filename Desired JSON filename. + */ + static void exportSettings(const Settings& settings, const char* filename); + + Options getOptions() const { return mOptions; } + bool isRunning() const { return mIsRunning; } + size_t currentTest() const { return mCurrentTest; } + size_t testCount() const { return mSpec->size(); } + bool isBatchModeEnabled() const { return mBatchModeEnabled; } + const char* getStatusMessage() const; + ~AutomationEngine(); + +private: + AutomationSpec const * const mSpec; + Settings * const mSettings; + Options mOptions; + + Engine* mColorGradingEngine = nullptr; + ColorGrading* mColorGrading = nullptr; + ColorGradingSettings mColorGradingSettings = {}; + + size_t mCurrentTest; + float mElapsedTime; + int mElapsedFrames; + bool mIsRunning = false; + bool mBatchModeEnabled = false; + bool mRequestStart = false; + bool mShouldClose = false; + bool mBatchModeAllowed = false; + bool mTerminated = false; + bool mOwnsSettings = false; + +public: + // For internal use from a screenshot callback. + void requestClose() { mShouldClose = true; } + bool isTerminated() const { return mTerminated; } +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_AUTOMATION_ENGINE_H diff --git a/package/android/libs/filament/include/viewer/AutomationSpec.h b/package/android/libs/filament/include/viewer/AutomationSpec.h new file mode 100644 index 00000000..49e16854 --- /dev/null +++ b/package/android/libs/filament/include/viewer/AutomationSpec.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_AUTOMATION_SPEC_H +#define VIEWER_AUTOMATION_SPEC_H + +#include + +#include + +namespace filament { +namespace viewer { + +/** + * Immutable list of Settings objects generated from a JSON spec. + * + * Each top-level item in the JSON spec is an object with "name", "base" and "permute". + * The "base" object specifies a single set of changes to apply to default settings. + * The optional "permute" object specifies a cross product of changes to apply to the base. + * + * The following example generates a total of 5 test cases. + * [{ + * "name": "simple", + * "base": { + * "view.dof.cocScale": 1.0, + * "view.bloom.strength": 0.5 + * }, + * "permute": { + * "view.bloom.enabled": [false, true], + * "view.dof.enabled": [false, true] + * } + * }, + * { + * "name": "ppoff", + * "base": { + * "view.postProcessingEnabled": false + * } + * }] + */ +class UTILS_PUBLIC AutomationSpec { +public: + + // Parses a JSON spec, then generates a list of Settings objects. + // Returns null on failure (see utils log for warnings and errors). + // Clients should release memory using "delete". + static AutomationSpec* generate(const char* jsonSpec, size_t size); + + // Generates a list of Settings objects using an embedded JSON spec. + static AutomationSpec* generateDefaultTestCases(); + + // Returns the number of generated Settings objects. + size_t size() const; + + // Gets a generated Settings object and copies it out. + // Returns false if the given index is out of bounds. + bool get(size_t index, Settings* out) const; + + // Returns the name of the JSON group for a given Settings object. + char const* getName(size_t index) const; + + // Frees all Settings objects and name strings. + ~AutomationSpec(); + +private: + struct Impl; + AutomationSpec(Impl*); + Impl* mImpl; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_AUTOMATION_SPEC_H diff --git a/package/android/libs/filament/include/viewer/RemoteServer.h b/package/android/libs/filament/include/viewer/RemoteServer.h new file mode 100644 index 00000000..6272b872 --- /dev/null +++ b/package/android/libs/filament/include/viewer/RemoteServer.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIEWER_REMOTE_SERVER_H +#define VIEWER_REMOTE_SERVER_H + +#include + +#include + +#include +#include + +class CivetServer; + +namespace filament { +namespace viewer { + +class MessageSender; +class MessageReceiver; + +/** + * Encapsulates a message sent from the web client. + * + * All instances of ReceivedMessage and their data / strings are owned by RemoteServer. + * These can be freed via RemoteServer::releaseReceivedMessage(). + */ +struct ReceivedMessage { + char* label; + char* buffer; + size_t bufferByteCount; + size_t messageUid; +}; + +/** + * Manages a tiny WebSocket server that can receive model data and viewer settings. + * + * Client apps can call peekReceivedMessage to check for new data, or acquireReceivedMessage + * to pop it off the small internal queue. When they are done examining the message contents + * they should call releaseReceivedMessage. + */ +class UTILS_PUBLIC RemoteServer { +public: + RemoteServer(int port = 8082); + ~RemoteServer(); + bool isValid() const { return mMessageSender; } + + /** + * Checks if a download is currently in progress and returns its label. + * Returns null if nothing is being downloaded. + */ + char const* peekIncomingLabel() const; + + /** + * Pops a message off the incoming queue or returns null if there are no unread messages. + * + * After examining its contents, users should free the message with releaseReceivedMessage. + */ + ReceivedMessage const* acquireReceivedMessage(); + + /** + * Frees the memory that holds the contents of a received message. + */ + void releaseReceivedMessage(ReceivedMessage const* message); + + void sendMessage(const Settings& settings); + void sendMessage(const char* label, const char* buffer, size_t bufsize); + + // For internal use (makes JNI simpler) + ReceivedMessage const* peekReceivedMessage() const; + +private: + void enqueueReceivedMessage(ReceivedMessage* message); + void setIncomingMessage(ReceivedMessage* message); + MessageSender* mMessageSender = nullptr; + MessageReceiver* mMessageReceiver = nullptr; + size_t mNextMessageUid = 0; + static const size_t kMessageCapacity = 4; + ReceivedMessage* mReceivedMessages[kMessageCapacity] = {}; + ReceivedMessage* mIncomingMessage = nullptr; + JsonSerializer mSerializer; + mutable std::mutex mReceivedMessagesMutex; + friend class MessageReceiver; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_REMOTE_SERVER_H diff --git a/package/android/libs/filament/include/viewer/Settings.h b/package/android/libs/filament/include/viewer/Settings.h new file mode 100644 index 00000000..6682260c --- /dev/null +++ b/package/android/libs/filament/include/viewer/Settings.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_SETTINGS_H +#define VIEWER_SETTINGS_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +namespace filament { + +using namespace color; + +class Skybox; +class Renderer; + +namespace viewer { + +struct ColorGradingSettings; +struct DynamicLightingSettings; +struct MaterialSettings; +struct Settings; +struct ViewSettings; +struct LightSettings; +struct ViewerOptions; + +enum class ToneMapping : uint8_t { + LINEAR = 0, + ACES_LEGACY = 1, + ACES = 2, + FILMIC = 3, + AGX = 4, + GENERIC = 5, + DISPLAY_RANGE = 6, +}; + +using AmbientOcclusionOptions = filament::View::AmbientOcclusionOptions; +using ScreenSpaceReflectionsOptions = filament::View::ScreenSpaceReflectionsOptions; +using AntiAliasing = filament::View::AntiAliasing; +using BloomOptions = filament::View::BloomOptions; +using DepthOfFieldOptions = filament::View::DepthOfFieldOptions; +using Dithering = filament::View::Dithering; +using FogOptions = filament::View::FogOptions; +using RenderQuality = filament::View::RenderQuality; +using ShadowType = filament::View::ShadowType; +using DynamicResolutionOptions = filament::View::DynamicResolutionOptions; +using MultiSampleAntiAliasingOptions = filament::View::MultiSampleAntiAliasingOptions; +using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions; +using VignetteOptions = filament::View::VignetteOptions; +using VsmShadowOptions = filament::View::VsmShadowOptions; +using GuardBandOptions = filament::View::GuardBandOptions; +using StereoscopicOptions = filament::View::StereoscopicOptions; +using LightManager = filament::LightManager; + +// These functions push all editable property values to their respective Filament objects. +void applySettings(Engine* engine, const ViewSettings& settings, View* dest); +void applySettings(Engine* engine, const MaterialSettings& settings, MaterialInstance* dest); +void applySettings(Engine* engine, const LightSettings& settings, IndirectLight* ibl, utils::Entity sunlight, + const utils::Entity* sceneLights, size_t sceneLightCount, LightManager* lm, Scene* scene, View* view); +void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera, Skybox* skybox, + Renderer* renderer); + +// Creates a new ColorGrading object based on the given settings. +UTILS_PUBLIC +ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine); + +class UTILS_PUBLIC JsonSerializer { +public: + JsonSerializer(); + ~JsonSerializer(); + + // Writes a human-readable JSON string into an internal buffer and returns the result. + const std::string& writeJson(const Settings& in); + + // Reads the given JSON blob and updates the corresponding fields in the given Settings object. + // - The given JSON blob need not specify all settings. + // - Returns true if successful. + // - This function writes warnings and error messages into the utils log. + bool readJson(const char* jsonChunk, size_t size, Settings* out); + +private: + class Context; + Context* context; +}; + +struct GenericToneMapperSettings { + float contrast = 1.55f; + float midGrayIn = 0.18f; + float midGrayOut = 0.215f; + float hdrMax = 10.0f; + bool operator!=(const GenericToneMapperSettings& rhs) const { return !(rhs == *this); } + bool operator==(const GenericToneMapperSettings& rhs) const; +}; + +struct AgxToneMapperSettings { + AgxToneMapper::AgxLook look = AgxToneMapper::AgxLook::NONE; + bool operator!=(const AgxToneMapperSettings& rhs) const { return !(rhs == *this); } + bool operator==(const AgxToneMapperSettings& rhs) const; +}; + +struct ColorGradingSettings { + // fields are ordered to avoid padding + bool enabled = true; + bool linkedCurves = false; + bool luminanceScaling = false; + bool gamutMapping = false; + filament::ColorGrading::QualityLevel quality = filament::ColorGrading::QualityLevel::MEDIUM; + ToneMapping toneMapping = ToneMapping::ACES_LEGACY; + bool padding0{}; + AgxToneMapperSettings agxToneMapper; + color::ColorSpace colorspace = Rec709-sRGB-D65; + GenericToneMapperSettings genericToneMapper; + math::float4 shadows{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 midtones{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 highlights{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 ranges{0.0f, 0.333f, 0.550f, 1.0f}; + math::float3 outRed{1.0f, 0.0f, 0.0f}; + math::float3 outGreen{0.0f, 1.0f, 0.0f}; + math::float3 outBlue{0.0f, 0.0f, 1.0f}; + math::float3 slope{1.0f}; + math::float3 offset{0.0f}; + math::float3 power{1.0f}; + math::float3 gamma{1.0f}; + math::float3 midPoint{1.0f}; + math::float3 scale{1.0f}; + float exposure = 0.0f; + float nightAdaptation = 0.0f; + float temperature = 0.0f; + float tint = 0.0f; + float contrast = 1.0f; + float vibrance = 1.0f; + float saturation = 1.0f; + + bool operator!=(const ColorGradingSettings &rhs) const { return !(rhs == *this); } + bool operator==(const ColorGradingSettings &rhs) const; +}; + +struct DynamicLightingSettings { + float zLightNear = 5; + float zLightFar = 100; +}; + +struct FogSettings { + Texture* fogColorTexture = nullptr; +}; + +// This defines fields in the same order as the setter methods in filament::View. +struct ViewSettings { + // standalone View settings + AntiAliasing antiAliasing = AntiAliasing::FXAA; + Dithering dithering = Dithering::TEMPORAL; + ShadowType shadowType = ShadowType::PCF; + bool postProcessingEnabled = true; + + // View Options (sorted) + AmbientOcclusionOptions ssao; + ScreenSpaceReflectionsOptions screenSpaceReflections; + BloomOptions bloom; + DepthOfFieldOptions dof; + DynamicResolutionOptions dsr; + FogOptions fog; + MultiSampleAntiAliasingOptions msaa; + RenderQuality renderQuality; + TemporalAntiAliasingOptions taa; + VignetteOptions vignette; + VsmShadowOptions vsmShadowOptions; + GuardBandOptions guardBand; + StereoscopicOptions stereoscopicOptions; + + // Custom View Options + ColorGradingSettings colorGrading; + DynamicLightingSettings dynamicLighting; + FogSettings fogSettings; +}; + +template +struct MaterialProperty { std::string name; T value; }; + +// This struct has a fixed size for simplicity. Each non-empty property name is an override. +struct MaterialSettings { + static constexpr size_t MAX_COUNT = 4; + MaterialProperty scalar[MAX_COUNT]; + MaterialProperty float3[MAX_COUNT]; + MaterialProperty float4[MAX_COUNT]; +}; + +struct LightSettings { + bool enableShadows = true; + bool enableSunlight = true; + LightManager::ShadowOptions shadowOptions; + SoftShadowOptions softShadowOptions; + float sunlightIntensity = 100000.0f; + float sunlightHaloSize = 10.0f; + float sunlightHaloFalloff = 80.0f; + float sunlightAngularRadius = 1.9f; + math::float3 sunlightDirection = {0.6, -1.0, -0.8}; + math::float3 sunlightColor = filament::Color::toLinear({ 0.98, 0.92, 0.89}); + float iblIntensity = 30000.0f; + float iblRotation = 0.0f; +}; + +struct ViewerOptions { + float cameraAperture = 16.0f; + float cameraSpeed = 125.0f; + float cameraISO = 100.0f; + float cameraNear = 0.1f; + float cameraFar = 100.0f; + float cameraEyeOcularDistance = 0.0f; + float cameraEyeToeIn = 0.0f; + float groundShadowStrength = 0.75f; + bool groundPlaneEnabled = false; + bool skyboxEnabled = true; + sRGBColor backgroundColor = { 0.0f }; + float cameraFocalLength = 28.0f; + float cameraFocusDistance = 10.0f; + bool autoScaleEnabled = true; + bool autoInstancingEnabled = false; +}; + +struct Settings { + ViewSettings view; + MaterialSettings material; + LightSettings lighting; + ViewerOptions viewer; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_SETTINGS_H diff --git a/package/android/libs/filament/include/viewer/ViewerGui.h b/package/android/libs/filament/include/viewer/ViewerGui.h new file mode 100644 index 00000000..8f843357 --- /dev/null +++ b/package/android/libs/filament/include/viewer/ViewerGui.h @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_VIEWERGUI_H +#define VIEWER_VIEWERGUI_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace filagui { + class ImGuiHelper; +} + +namespace filament { +namespace viewer { + +/** + * \class ViewerGui ViewerGui.h viewer/ViewerGui.h + * \brief Builds ImGui widgets for a simple glTF viewer and manages the associated state. + * + * This is a utility that can be used across multiple platforms, including web. + * + * \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader + * instead. + */ +class UTILS_PUBLIC ViewerGui { +public: + using Animator = gltfio::Animator; + using FilamentAsset = gltfio::FilamentAsset; + using FilamentInstance = gltfio::FilamentInstance; + + static constexpr int DEFAULT_SIDEBAR_WIDTH = 350; + + /** + * Constructs a ViewerGui that has a fixed association with the given Filament objects. + * + * Upon construction, the simple viewer may create some additional Filament objects (such as + * light sources) that it owns. + */ + ViewerGui(Engine* engine, Scene* scene, View* view, + int sidebarWidth = DEFAULT_SIDEBAR_WIDTH); + + /** + * Destroys the ViewerGui and any Filament entities that it owns. + */ + ~ViewerGui(); + + /** + * Sets the viewer's current asset and instance. + * + * The viewer does not claim ownership over the asset or its entities. Clients should use + * AssetLoader and ResourceLoader to load an asset before passing it in. + * + * This method does not add renderables to the scene; see populateScene(). + * + * @param instance The asset to view. + * @param instance The instance to view. + */ + void setAsset(FilamentAsset* asset, FilamentInstance* instance); + + /** + * Adds the asset's ready-to-render entities into the scene. + * + * This is used for asychronous loading. It can be called once per frame to gradually add + * entities into the scene as their textures are loaded. + */ + void populateScene(); + + /** + * Removes the current asset from the viewer. + * + * This removes all the asset entities from the Scene, but does not destroy them. + */ + void removeAsset(); + + /** + * Sets or changes the current scene's IBL to allow the UI manipulate it. + */ + void setIndirectLight(IndirectLight* ibl, math::float3 const* sh3); + + /** + * Applies the currently-selected glTF animation to the transformation hierarchy and updates + * the bone matrices on all renderables. + * + * If an instance is provided, animation is applied to it rather than the "set" instance. + */ + void applyAnimation(double currentTime, FilamentInstance* instance = nullptr); + + /** + * Constructs ImGui controls for the current frame and responds to everything that the user has + * changed since the previous frame. + * + * If desired this can be used in conjunction with the filagui library, which allows clients to + * render ImGui controls with Filament. + */ + void updateUserInterface(); + + /** + * Alternative to updateUserInterface that uses an internal instance of ImGuiHelper. + * + * This utility method is designed for clients that do not want to manage their own instance of + * ImGuiHelper (e.g., JavaScript clients). + * + * Behind the scenes this simply calls ImGuiHelper->render() and passes updateUserInterface into + * its callback. Note that the first call might be slower since it requires the creation of the + * internal ImGuiHelper instance. + */ + void renderUserInterface(float timeStepInSeconds, View* guiView, float pixelRatio); + + /** + * Event-passing methods, useful only when ViewerGui manages its own instance of ImGuiHelper. + * The key codes used in these methods are just normal ASCII/ANSI codes. + * @{ + */ + void mouseEvent(float mouseX, float mouseY, bool mouseButton, float mouseWheelY, bool control); + void keyDownEvent(int keyCode); + void keyUpEvent(int keyCode); + void keyPressEvent(int charCode); + /** @}*/ + + /** + * Retrieves the current width of the ImGui "window" which we are using as a sidebar. + * Clients can monitor this value to adjust the size of the view. + */ + int getSidebarWidth() const { return mSidebarWidth; } + + /** + * Allows clients to inject custom UI. + */ + void setUiCallback(std::function callback) { mCustomUI = callback; } + + /** + * Draws the bounding box of each renderable. + * Defaults to false. + */ + void enableWireframe(bool b) { mEnableWireframe = b; } + + /** + * Enables a built-in light source (useful for creating shadows). + * Defaults to true. + */ + void enableSunlight(bool b) { mSettings.lighting.enableSunlight = b; } + + /** + * Enables dithering on the view. + * Defaults to true. + */ + void enableDithering(bool b) { + mSettings.view.dithering = b ? Dithering::TEMPORAL : Dithering::NONE; + } + + /** + * Enables FXAA antialiasing in the post-process pipeline. + * Defaults to true. + */ + void enableFxaa(bool b) { + mSettings.view.antiAliasing = b ? AntiAliasing::FXAA : AntiAliasing::NONE; + } + + /** + * Enables hardware-based MSAA antialiasing. + * Defaults to true. + */ + void enableMsaa(bool b) { + mSettings.view.msaa.sampleCount = 4; + mSettings.view.msaa.enabled = b; + } + + /** + * Enables screen-space ambient occlusion in the post-process pipeline. + * Defaults to true. + */ + void enableSSAO(bool b) { mSettings.view.ssao.enabled = b; } + + /** + * Enables Bloom. + * Defaults to true. + */ + void enableBloom(bool bloom) { mSettings.view.bloom.enabled = bloom; } + + /** + * Adjusts the intensity of the IBL. + * See also IndirectLight::setIntensity(). + * Defaults to 30000.0. + */ + void setIBLIntensity(float brightness) { mSettings.lighting.iblIntensity = brightness; } + + /** + * Updates the transform at the root node according to the autoScaleEnabled setting. + */ + void updateRootTransform(); + + /** + * Gets a modifiable reference to stashed state. + */ + Settings& getSettings() { return mSettings; } + + void stopAnimation() { mCurrentAnimation = -1; } + + int getCurrentCamera() const { return mCurrentCamera; } + +private: + using SceneMask = gltfio::NodeManager::SceneMask; + + bool isRemoteMode() const { return mAsset == nullptr; } + + void sceneSelectionUI(); + + // Immutable properties set from the constructor. + Engine* const mEngine; + Scene* const mScene; + View* const mView; + const utils::Entity mSunlight; + + // Lazily instantiated fields. + filagui::ImGuiHelper* mImGuiHelper = nullptr; + + // Properties that can be changed from the application. + FilamentAsset* mAsset = nullptr; + FilamentInstance* mInstance = nullptr; + IndirectLight* mIndirectLight = nullptr; + std::function mCustomUI; + + // Properties that can be changed from the UI. + int mCurrentAnimation = 0; // -1 means not playing animation and count means plays all of them (0-based index) + int mCurrentVariant = 0; + bool mEnableWireframe = false; + int mVsmMsaaSamplesLog2 = 1; + Settings mSettings; + int mSidebarWidth; + uint32_t mFlags; + utils::Entity mCurrentMorphingEntity; + std::vector mMorphWeights; + SceneMask mVisibleScenes; + bool mShowingRestPose = false; + + // 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 = -1; // zero-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]; + float mCurvePlot[1024 * 3]; +}; + +UTILS_PUBLIC +math::mat4f fitIntoUnitCube(const Aabb& bounds, float zoffset); + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_VIEWERGUI_H diff --git a/package/ios/libs/filament/LICENSE b/package/ios/libs/filament/LICENSE new file mode 100644 index 00000000..73774b41 --- /dev/null +++ b/package/ios/libs/filament/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 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. diff --git a/package/ios/libs/filament/README.md b/package/ios/libs/filament/README.md new file mode 100644 index 00000000..79ec596b --- /dev/null +++ b/package/ios/libs/filament/README.md @@ -0,0 +1,182 @@ +# Filament + +This package contains several executables and libraries you can use to build applications using +Filament. Latest versions are available on the [project page](https://github.com/google/filament). + +## Binaries + +- `cmgen`, Image-based lighting asset generator +- `filamesh`, Mesh converter +- `glslminifier`, Tool to minify GLSL shaders +- `gltf_viewer`, glTF 2.0 viewer that lets you explore many features of Filament +- `matc`, Material compiler +- `material_sandbox`, simple mesh viewer that lets you explore material and lighting features +- `matinfo`, Displays information about materials compiled with `matc` +- `mipgen`, Generates a series of miplevels from a source image. +- `normal-blending`, Tool to blend normal maps +- `resgen`, Tool to convert files into binary resources to be embedded at compie time +- `roughness-prefilter`, Pre-filters a roughness map from a normal map to reduce aliasing +- `specular-color`, Computes the specular color of conductors based on spectral data + +You can refer to the individual documentation files in `docs/` for more information. + +## Libraries + +Filament is distributed as a set of static libraries you must link against: + +- `backend`, Required, implements all backends +- `bluegl`, Required to render with OpenGL or OpenGL ES +- `bluevk`, Required to render with Vulkan +- `filabridge`, Support library for Filament +- `filaflat`, Support library for Filament +- `filament`, Main Filament library +- `backend`, Filament render backend library +- `ibl`, Image-based lighting support library +- `utils`, Support library for Filament +- `geometry`, Geometry helper library for Filament +- `smol-v`, SPIR-V compression library, used only with Vulkan support + +To use Filament from Java you must use the following two libraries instead: +- `filament-java.jar`, Contains Filament's Java classes +- `filament-jni`, Filament's JNI bindings + +To link against debug builds of Filament, you must also link against: + +- `matdbg`, Support library that adds an interactive web-based debugger to Filament + +To use the Vulkan backend on macOS you must install the LunarG SDK, enable "System Global +Components", and reboot your machine. + +The easiest way to install those files is to use the macOS +[LunarG Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) installer. + +## Linking against Filament + +This walkthrough will get you successfully compiling and linking native code +against Filament with minimum dependencies. + +To start, download Filament's [latest binary release](https://github.com/google/filament/releases) +and extract into a directory of your choosing. Binary releases are suffixed +with the platform name, for example, `filament-20181009-linux.tgz`. + +Create a file, `main.cpp`, in the same directory with the following contents: + +```c++ +#include +#include + +using namespace filament; + +int main(int argc, char** argv) +{ + Engine *engine = Engine::create(); + engine->destroy(&engine); + return 0; +} +``` + +The directory should look like: + +``` +|-- README.md +|-- bin +|-- docs +|-- include +|-- lib +|-- main.cpp +``` + +We'll use a platform-specific Makefile to compile and link `main.cpp` with Filament's libraries. +Copy your platform's Makefile below into a `Makefile` inside the same directory. + +### Linux + +```make +FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl +CC=clang++ + +main: main.o + $(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) -lpthread -lc++ -ldl -o main + +main.o: main.cpp + $(CC) -Iinclude/ -std=c++17 -pthread -c main.cpp + +clean: + rm -f main main.o + +.PHONY: clean +``` + +### macOS + +```make +FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl +FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo +CC=clang++ + +main: main.o + $(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main + +main.o: main.cpp + $(CC) -Iinclude/ -std=c++17 -c main.cpp + +clean: + rm -f main main.o + +.PHONY: clean +``` + +### Windows + +Note that the static libraries distributed for Windows include several +variants: mt, md, mtd, mdd. These correspond to the [run-time library +flags](https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=vs-2017) +`/MT`, `/MD`, `/MTd`, and `/MDd`, respectively. Here we use the mt variant. For the debug variants, +be sure to also include `matdbg.lib` in `FILAMENT_LIBS`. + +When building Filament from source, the `USE_STATIC_CRT` CMake option can be +used to change the run-time library version. + +```make +FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \ + utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib +CC=cl.exe + +main.exe: main.obj + $(CC) main.obj /link /libpath:"lib\\x86_64\\mt\\" $(FILAMENT_LIBS) \ + gdi32.lib user32.lib opengl32.lib + +main.obj: main.cpp + $(CC) /MT /Iinclude\\ /std:c++17 /c main.cpp + +clean: + del main.exe main.obj + +.PHONY: clean +``` + +### Compiling + +You should be able to invoke `make` and run the executable successfully: + +``` +$ make +$ ./main +FEngine (64 bits) created at 0x106471000 (threading is enabled) +``` + +On Windows, you'll need to open up a Visual Studio Native Tools Command Prompt +and invoke `nmake` instead of `make`. + + +### Generating C++ documentation + +To generate the documentation you must first install `doxygen` and `graphviz`, then run the +following commands: + +```shell +cd filament/filament +doxygen docs/doxygen/filament.doxygen +``` + +Finally simply open `docs/html/index.html` in your web browser. diff --git a/package/ios/libs/filament/include/backend/AcquiredImage.h b/package/ios/libs/filament/include/backend/AcquiredImage.h new file mode 100644 index 00000000..fec27a53 --- /dev/null +++ b/package/ios/libs/filament/include/backend/AcquiredImage.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H +#define TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H + +#include + +namespace filament::backend { + +class CallbackHandler; + +// This lightweight POD allows us to bundle the state required to process an ACQUIRED stream. +// Since these types of external images need to be moved around and queued up, an encapsulation is +// very useful. + +struct AcquiredImage { + void* image = nullptr; + backend::StreamCallback callback = nullptr; + void* userData = nullptr; + CallbackHandler* handler = nullptr; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_ACQUIREDIMAGE_H diff --git a/package/ios/libs/filament/include/backend/BufferDescriptor.h b/package/ios/libs/filament/include/backend/BufferDescriptor.h new file mode 100644 index 00000000..ebb57537 --- /dev/null +++ b/package/ios/libs/filament/include/backend/BufferDescriptor.h @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H + +#include +#include + +#include + +namespace filament::backend { + +class CallbackHandler; + +/** + * A CPU memory-buffer descriptor, typically used to transfer data from the CPU to the GPU. + * + * A BufferDescriptor owns the memory buffer it references, therefore BufferDescriptor cannot + * be copied, but can be moved. + * + * BufferDescriptor releases ownership of the memory-buffer when it's destroyed. + */ +class UTILS_PUBLIC BufferDescriptor { +public: + /** + * Callback used to destroy the buffer data. + * Guarantees: + * Called on the main filament thread. + * + * Limitations: + * Must be lightweight. + * Must not call filament APIs. + */ + using Callback = void(*)(void* buffer, size_t size, void* user); + + //! creates an empty descriptor + BufferDescriptor() noexcept = default; + + //! calls the callback to advertise BufferDescriptor no-longer owns the buffer + ~BufferDescriptor() noexcept { + if (mCallback) { + mCallback(buffer, size, mUser); + } + } + + BufferDescriptor(const BufferDescriptor& rhs) = delete; + BufferDescriptor& operator=(const BufferDescriptor& rhs) = delete; + + BufferDescriptor(BufferDescriptor&& rhs) noexcept + : buffer(rhs.buffer), size(rhs.size), + mCallback(rhs.mCallback), mUser(rhs.mUser), mHandler(rhs.mHandler) { + rhs.buffer = nullptr; + rhs.mCallback = nullptr; + } + + BufferDescriptor& operator=(BufferDescriptor&& rhs) noexcept { + if (this != &rhs) { + buffer = rhs.buffer; + size = rhs.size; + mCallback = rhs.mCallback; + mUser = rhs.mUser; + mHandler = rhs.mHandler; + rhs.buffer = nullptr; + rhs.mCallback = nullptr; + } + return *this; + } + + /** + * Creates a BufferDescriptor that references a CPU memory-buffer + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param callback A callback used to release the CPU buffer from this BufferDescriptor + * @param user An opaque user pointer passed to the callback function when it's called + */ + BufferDescriptor(void const* buffer, size_t size, + Callback callback = nullptr, void* user = nullptr) noexcept + : buffer(const_cast(buffer)), size(size), mCallback(callback), mUser(user) { + } + + /** + * Creates a BufferDescriptor that references a CPU memory-buffer + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param callback A callback used to release the CPU buffer from this BufferDescriptor + * @param user An opaque user pointer passed to the callback function when it's called + */ + BufferDescriptor(void const* buffer, size_t size, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : buffer(const_cast(buffer)), size(size), + mCallback(callback), mUser(user), mHandler(handler) { + } + + // -------------------------------------------------------------------------------------------- + + /** + * Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed + * by pointer as the callback. e.g.: + * auto bd = BufferDescriptor::make(buffer, size, foo); + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param handler Handler to use to dispatch the callback, or nullptr for the default handler + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make(void const* buffer, size_t size, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { + buffer, size, + handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); + }, data + }; + } + + /** + * Helper to create a BufferDescriptor that uses a functor as the callback. + * + * Caveats: + * - DO NOT CALL setCallback() when using this helper. + * - This make a heap allocation + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param functor functor of type f(void const* buffer, size_t size) + * @param handler Handler to use to dispatch the callback, or nullptr for the default handler + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make(void const* buffer, size_t size, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { + buffer, size, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, + new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + + /** + * Set or replace the release callback function + * @param callback The new callback function + * @param user An opaque user pointer passed to the callbeck function when it's called + */ + void setCallback(Callback callback, void* user = nullptr) noexcept { + this->mCallback = callback; + this->mUser = user; + this->mHandler = nullptr; + } + + /** + * Set or replace the release callback function + * @param handler The Handler to use to dispatch the callback + * @param callback The new callback function + * @param user An opaque user pointer passed to the callbeck function when it's called + */ + void setCallback(CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept { + mCallback = callback; + mUser = user; + mHandler = handler; + } + + //! Returns whether a release callback is set + bool hasCallback() const noexcept { return mCallback != nullptr; } + + //! Returns the currently set release callback function + Callback getCallback() const noexcept { + return mCallback; + } + + //! Returns the handler for this callback or nullptr if the default handler is to be used. + CallbackHandler* getHandler() const noexcept { + return mHandler; + } + + //! Returns the user opaque pointer associated to this BufferDescriptor + void* getUser() const noexcept { + return mUser; + } + + //! CPU memory-buffer virtual address + void* buffer = nullptr; + + //! CPU memory-buffer size in bytes + size_t size = 0; + +private: + // callback when the buffer is consumed. + Callback mCallback = nullptr; + void* mUser = nullptr; + CallbackHandler* mHandler = nullptr; +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::BufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H diff --git a/package/ios/libs/filament/include/backend/CallbackHandler.h b/package/ios/libs/filament/include/backend/CallbackHandler.h new file mode 100644 index 00000000..036031a9 --- /dev/null +++ b/package/ios/libs/filament/include/backend/CallbackHandler.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H +#define TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H + +namespace filament::backend { + +/** + * A generic interface to dispatch callbacks. + * + * All APIs that take a callback as argument also take a + * CallbackHandler* which is used to dispatch the + * callback: CallbackHandler::post() method is called from a service thread as soon + * as possible (this will NEVER be the main thread), CallbackHandler::post() + * is responsible for scheduling the callback onto the thread the + * user desires. + * + * This is intended to make callbacks interoperate with + * the platform/OS's own messaging system. + * + * CallbackHandler* can always be nullptr in which case the default handler is used. The + * default handler always dispatches callbacks on filament's main thread opportunistically. + * + * Life time: + * --------- + * + * Filament make no attempts to manage the life time of the CallbackHandler* and never takes + * ownership. + * In particular, this means that the CallbackHandler instance must stay valid until all + * pending callbacks are been dispatched. + * + * Similarly, when shutting down filament, care must be taken to ensure that all pending callbacks + * that might access filament's state have been dispatched. Filament can no longer ensure this + * because callback execution is the responsibility of the CallbackHandler, which is external to + * filament. + * Typically, the concrete CallbackHandler would have a mechanism to drain and/or wait for all + * callbacks to be processed. + * + */ +class CallbackHandler { +public: + using Callback = void(*)(void* user); + + /** + * Schedules the callback to be called onto the appropriate thread. + * Typically this will be the application's main thead. + * + * Must be thread-safe. + */ + virtual void post(void* user, Callback callback) = 0; + +protected: + virtual ~CallbackHandler() = default; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H diff --git a/package/ios/libs/filament/include/backend/DriverApiForward.h b/package/ios/libs/filament/include/backend/DriverApiForward.h new file mode 100644 index 00000000..9cc56c03 --- /dev/null +++ b/package/ios/libs/filament/include/backend/DriverApiForward.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H +#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H + +namespace filament::backend { + +class CommandStream; + +using DriverApi = CommandStream; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H diff --git a/package/ios/libs/filament/include/backend/DriverEnums.h b/package/ios/libs/filament/include/backend/DriverEnums.h new file mode 100644 index 00000000..c41d1b83 --- /dev/null +++ b/package/ios/libs/filament/include/backend/DriverEnums.h @@ -0,0 +1,1269 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_DRIVERENUMS_H +#define TNT_FILAMENT_BACKEND_DRIVERENUMS_H + +#include +#include // Because we define ERROR in the FenceStatus enum. + +#include + +#include + +#include + +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers + +#include +#include + +/** + * Types and enums used by filament's driver. + * + * Effectively these types are public but should not be used directly. Instead use public classes + * internal redeclaration of these types. + * For e.g. Use Texture::Sampler instead of filament::SamplerType. + */ +namespace filament::backend { + +/** + * Requests a SwapChain with an alpha channel. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1; + +/** + * This flag indicates that the swap chain may be used as a source surface + * for reading back render results. This config flag must be set when creating + * any SwapChain that will be used as the source for a blit operation. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2; + +/** + * Indicates that the native X11 window is an XCB window rather than an XLIB window. + * This is ignored on non-Linux platforms and in builds that support only one X11 API. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4; + +/** + * Indicates that the native window is a CVPixelBufferRef. + * + * This is only supported by the Metal backend. The CVPixelBuffer must be in the + * kCVPixelFormatType_32BGRA format. + * + * It is not necessary to add an additional retain call before passing the pixel buffer to + * Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and + * CVPixelBufferRelease when the swap chain is destroyed. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8; + +/** + * Indicates that the SwapChain must automatically perform linear to srgb encoding. + */ +static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10; + +/** + * Indicates that the SwapChain should also contain a stencil component. + */ +static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = 0x20; + + +static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES. +static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3. +static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects. +static constexpr size_t MAX_SSBO_COUNT = 4; // This is guaranteed by OpenGL ES. + +// Per feature level caps +// Use (int)FeatureLevel to index this array +static constexpr struct { + const size_t MAX_VERTEX_SAMPLER_COUNT; + const size_t MAX_FRAGMENT_SAMPLER_COUNT; +} FEATURE_LEVEL_CAPS[4] = { + { 0, 0 }, // do not use + { 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal + { 16, 16 }, // guaranteed by OpenGL ES, Vulkan and Metal + { 31, 31 }, // guaranteed by Metal +}; + +static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT, + "The number of buffer objects that can be attached to a VertexBuffer must be " + "less than or equal to the maximum number of vertex attributes."); + +static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 10; // This is guaranteed by OpenGL ES. +static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES. + +/** + * Defines the backend's feature levels. + */ +enum class FeatureLevel : uint8_t { + FEATURE_LEVEL_0 = 0, //!< OpenGL ES 2.0 features + FEATURE_LEVEL_1, //!< OpenGL ES 3.0 features (default) + FEATURE_LEVEL_2, //!< OpenGL ES 3.1 features + 16 textures units + cubemap arrays + FEATURE_LEVEL_3 //!< OpenGL ES 3.1 features + 31 textures units + cubemap arrays +}; + +/** + * Selects which driver a particular Engine should use. + */ +enum class Backend : uint8_t { + DEFAULT = 0, //!< Automatically selects an appropriate driver for the platform. + OPENGL = 1, //!< Selects the OpenGL/ES driver (default on Android) + VULKAN = 2, //!< Selects the Vulkan driver if the platform supports it (default on Linux/Windows) + METAL = 3, //!< Selects the Metal driver if the platform supports it (default on MacOS/iOS). + NOOP = 4, //!< Selects the no-op driver for testing purposes. +}; + +static constexpr const char* backendToString(Backend backend) { + switch (backend) { + case Backend::NOOP: + return "Noop"; + case Backend::OPENGL: + return "OpenGL"; + case Backend::VULKAN: + return "Vulkan"; + case Backend::METAL: + return "Metal"; + default: + return "Unknown"; + } +} + +/** + * Defines the shader language. Similar to the above backend enum, but the OpenGL backend can select + * between two shader languages: ESSL 1.0 and ESSL 3.0. + */ +enum class ShaderLanguage { + ESSL1 = 0, + ESSL3 = 1, + SPIRV = 2, + MSL = 3, +}; + +static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) { + switch (shaderLanguage) { + case ShaderLanguage::ESSL1: + return "ESSL 1.0"; + case ShaderLanguage::ESSL3: + return "ESSL 3.0"; + case ShaderLanguage::SPIRV: + return "SPIR-V"; + case ShaderLanguage::MSL: + return "MSL"; + } +} + +/** + * Bitmask for selecting render buffers + */ +enum class TargetBufferFlags : uint32_t { + NONE = 0x0u, //!< No buffer selected. + COLOR0 = 0x00000001u, //!< Color buffer selected. + COLOR1 = 0x00000002u, //!< Color buffer selected. + COLOR2 = 0x00000004u, //!< Color buffer selected. + COLOR3 = 0x00000008u, //!< Color buffer selected. + COLOR4 = 0x00000010u, //!< Color buffer selected. + COLOR5 = 0x00000020u, //!< Color buffer selected. + COLOR6 = 0x00000040u, //!< Color buffer selected. + COLOR7 = 0x00000080u, //!< Color buffer selected. + + COLOR = COLOR0, //!< \deprecated + COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7, + DEPTH = 0x10000000u, //!< Depth buffer selected. + STENCIL = 0x20000000u, //!< Stencil buffer selected. + DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. + ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. +}; + +inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept { + if (index == 0u) return TargetBufferFlags::COLOR0; + if (index == 1u) return TargetBufferFlags::COLOR1; + if (index == 2u) return TargetBufferFlags::COLOR2; + if (index == 3u) return TargetBufferFlags::COLOR3; + if (index == 4u) return TargetBufferFlags::COLOR4; + if (index == 5u) return TargetBufferFlags::COLOR5; + if (index == 6u) return TargetBufferFlags::COLOR6; + if (index == 7u) return TargetBufferFlags::COLOR7; + if (index == 8u) return TargetBufferFlags::DEPTH; + if (index == 9u) return TargetBufferFlags::STENCIL; + return TargetBufferFlags::NONE; +} + +/** + * Frequency at which a buffer is expected to be modified and used. This is used as an hint + * for the driver to make better decisions about managing memory internally. + */ +enum class BufferUsage : uint8_t { + STATIC, //!< content modified once, used many times + DYNAMIC, //!< content modified frequently, used many times +}; + +/** + * Defines a viewport, which is the origin and extent of the clip-space. + * All drawing is clipped to the viewport. + */ +struct Viewport { + int32_t left; //!< left coordinate in window space. + int32_t bottom; //!< bottom coordinate in window space. + uint32_t width; //!< width in pixels + uint32_t height; //!< height in pixels + //! get the right coordinate in window space of the viewport + int32_t right() const noexcept { return left + int32_t(width); } + //! get the top coordinate in window space of the viewport + int32_t top() const noexcept { return bottom + int32_t(height); } +}; + + +/** + * Specifies the mapping of the near and far clipping plane to window coordinates. + */ +struct DepthRange { + float near = 0.0f; //!< mapping of the near plane to window coordinates. + float far = 1.0f; //!< mapping of the far plane to window coordinates. +}; + +/** + * Error codes for Fence::wait() + * @see Fence, Fence::wait() + */ +enum class FenceStatus : int8_t { + ERROR = -1, //!< An error occurred. The Fence condition is not satisfied. + CONDITION_SATISFIED = 0, //!< The Fence condition is satisfied. + TIMEOUT_EXPIRED = 1, //!< wait()'s timeout expired. The Fence condition is not satisfied. +}; + +/** + * Status codes for sync objects + */ +enum class SyncStatus : int8_t { + ERROR = -1, //!< An error occurred. The Sync is not signaled. + SIGNALED = 0, //!< The Sync is signaled. + NOT_SIGNALED = 1, //!< The Sync is not signaled yet +}; + +static constexpr uint64_t FENCE_WAIT_FOR_EVER = uint64_t(-1); + +/** + * Shader model. + * + * These enumerants are used across all backends and refer to a level of functionality and quality. + * + * For example, the OpenGL backend returns `MOBILE` if it supports OpenGL ES, or `DESKTOP` if it + * supports Desktop OpenGL, this is later used to select the proper shader. + * + * Shader quality vs. performance is also affected by ShaderModel. + */ +enum class ShaderModel : uint8_t { + MOBILE = 1, //!< Mobile level functionality + DESKTOP = 2, //!< Desktop level functionality +}; +static constexpr size_t SHADER_MODEL_COUNT = 2; + +/** + * Primitive types + */ +enum class PrimitiveType : uint8_t { + // don't change the enums values (made to match GL) + POINTS = 0, //!< points + LINES = 1, //!< lines + LINE_STRIP = 3, //!< line strip + TRIANGLES = 4, //!< triangles + TRIANGLE_STRIP = 5 //!< triangle strip +}; + +/** + * Supported uniform types + */ +enum class UniformType : uint8_t { + BOOL, + BOOL2, + BOOL3, + BOOL4, + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4, + INT, + INT2, + INT3, + INT4, + UINT, + UINT2, + UINT3, + UINT4, + MAT3, //!< a 3x3 float matrix + MAT4, //!< a 4x4 float matrix + STRUCT +}; + +/** + * Supported constant parameter types + */ + enum class ConstantType : uint8_t { + INT, + FLOAT, + BOOL +}; + +enum class Precision : uint8_t { + LOW, + MEDIUM, + HIGH, + DEFAULT +}; + +/** + * Shader compiler priority queue + */ +enum class CompilerPriorityQueue : uint8_t { + HIGH, + LOW +}; + +//! Texture sampler type +enum class SamplerType : uint8_t { + SAMPLER_2D, //!< 2D texture + SAMPLER_2D_ARRAY, //!< 2D array texture + SAMPLER_CUBEMAP, //!< Cube map texture + SAMPLER_EXTERNAL, //!< External texture + SAMPLER_3D, //!< 3D texture + SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2) +}; + +//! Subpass type +enum class SubpassType : uint8_t { + SUBPASS_INPUT +}; + +//! Texture sampler format +enum class SamplerFormat : uint8_t { + INT = 0, //!< signed integer sampler + UINT = 1, //!< unsigned integer sampler + FLOAT = 2, //!< float sampler + SHADOW = 3 //!< shadow sampler (PCF) +}; + +/** + * Supported element types + */ +enum class ElementType : uint8_t { + BYTE, + BYTE2, + BYTE3, + BYTE4, + UBYTE, + UBYTE2, + UBYTE3, + UBYTE4, + SHORT, + SHORT2, + SHORT3, + SHORT4, + USHORT, + USHORT2, + USHORT3, + USHORT4, + INT, + UINT, + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4, + HALF, + HALF2, + HALF3, + HALF4, +}; + +//! Buffer object binding type +enum class BufferObjectBinding : uint8_t { + VERTEX, + UNIFORM, + SHADER_STORAGE +}; + +//! Face culling Mode +enum class CullingMode : uint8_t { + NONE, //!< No culling, front and back faces are visible + FRONT, //!< Front face culling, only back faces are visible + BACK, //!< Back face culling, only front faces are visible + FRONT_AND_BACK //!< Front and Back, geometry is not visible +}; + +//! Pixel Data Format +enum class PixelDataFormat : uint8_t { + R, //!< One Red channel, float + R_INTEGER, //!< One Red channel, integer + RG, //!< Two Red and Green channels, float + RG_INTEGER, //!< Two Red and Green channels, integer + RGB, //!< Three Red, Green and Blue channels, float + RGB_INTEGER, //!< Three Red, Green and Blue channels, integer + RGBA, //!< Four Red, Green, Blue and Alpha channels, float + RGBA_INTEGER, //!< Four Red, Green, Blue and Alpha channels, integer + UNUSED, // used to be rgbm + DEPTH_COMPONENT, //!< Depth, 16-bit or 24-bits usually + DEPTH_STENCIL, //!< Two Depth (24-bits) + Stencil (8-bits) channels + ALPHA //! One Alpha channel, float +}; + +//! Pixel Data Type +enum class PixelDataType : uint8_t { + UBYTE, //!< unsigned byte + BYTE, //!< signed byte + USHORT, //!< unsigned short (16-bit) + SHORT, //!< signed short (16-bit) + UINT, //!< unsigned int (32-bit) + INT, //!< signed int (32-bit) + HALF, //!< half-float (16-bit float) + FLOAT, //!< float (32-bits float) + COMPRESSED, //!< compressed pixels, @see CompressedPixelDataType + UINT_10F_11F_11F_REV, //!< three low precision floating-point numbers + USHORT_565, //!< unsigned int (16-bit), encodes 3 RGB channels + UINT_2_10_10_10_REV, //!< unsigned normalized 10 bits RGB, 2 bits alpha +}; + +//! Compressed pixel data types +enum class CompressedPixelDataType : uint16_t { + // Mandatory in GLES 3.0 and GL 4.3 + EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, + ETC2_RGB8, ETC2_SRGB8, + ETC2_RGB8_A1, ETC2_SRGB8_A1, + ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, + + // Available everywhere except Android/iOS + DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, + DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, + + // ASTC formats are available with a GLES extension + RGBA_ASTC_4x4, + RGBA_ASTC_5x4, + RGBA_ASTC_5x5, + RGBA_ASTC_6x5, + RGBA_ASTC_6x6, + RGBA_ASTC_8x5, + RGBA_ASTC_8x6, + RGBA_ASTC_8x8, + RGBA_ASTC_10x5, + RGBA_ASTC_10x6, + RGBA_ASTC_10x8, + RGBA_ASTC_10x10, + RGBA_ASTC_12x10, + RGBA_ASTC_12x12, + SRGB8_ALPHA8_ASTC_4x4, + SRGB8_ALPHA8_ASTC_5x4, + SRGB8_ALPHA8_ASTC_5x5, + SRGB8_ALPHA8_ASTC_6x5, + SRGB8_ALPHA8_ASTC_6x6, + SRGB8_ALPHA8_ASTC_8x5, + SRGB8_ALPHA8_ASTC_8x6, + SRGB8_ALPHA8_ASTC_8x8, + SRGB8_ALPHA8_ASTC_10x5, + SRGB8_ALPHA8_ASTC_10x6, + SRGB8_ALPHA8_ASTC_10x8, + SRGB8_ALPHA8_ASTC_10x10, + SRGB8_ALPHA8_ASTC_12x10, + SRGB8_ALPHA8_ASTC_12x12, + + // RGTC formats available with a GLES extension + RED_RGTC1, // BC4 unsigned + SIGNED_RED_RGTC1, // BC4 signed + RED_GREEN_RGTC2, // BC5 unsigned + SIGNED_RED_GREEN_RGTC2, // BC5 signed + + // BPTC formats available with a GLES extension + RGB_BPTC_SIGNED_FLOAT, // BC6H signed + RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned + RGBA_BPTC_UNORM, // BC7 + SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB +}; + +/** Supported texel formats + * These formats are typically used to specify a texture's internal storage format. + * + * Enumerants syntax format + * ======================== + * + * `[components][size][type]` + * + * `components` : List of stored components by this format.\n + * `size` : Size in bit of each component.\n + * `type` : Type this format is stored as.\n + * + * + * Name | Component + * :--------|:------------------------------- + * R | Linear Red + * RG | Linear Red, Green + * RGB | Linear Red, Green, Blue + * RGBA | Linear Red, Green Blue, Alpha + * SRGB | sRGB encoded Red, Green, Blue + * DEPTH | Depth + * STENCIL | Stencil + * + * \n + * Name | Type + * :--------|:--------------------------------------------------- + * (none) | Unsigned Normalized Integer [0, 1] + * _SNORM | Signed Normalized Integer [-1, 1] + * UI | Unsigned Integer @f$ [0, 2^{size}] @f$ + * I | Signed Integer @f$ [-2^{size-1}, 2^{size-1}-1] @f$ + * F | Floating-point + * + * + * Special color formats + * --------------------- + * + * There are a few special color formats that don't follow the convention above: + * + * Name | Format + * :----------------|:-------------------------------------------------------------------------- + * RGB565 | 5-bits for R and B, 6-bits for G. + * RGB5_A1 | 5-bits for R, G and B, 1-bit for A. + * RGB10_A2 | 10-bits for R, G and B, 2-bits for A. + * RGB9_E5 | **Unsigned** floating point. 9-bits mantissa for RGB, 5-bits shared exponent + * R11F_G11F_B10F | **Unsigned** floating point. 6-bits mantissa, for R and G, 5-bits for B. 5-bits exponent. + * SRGB8_A8 | sRGB 8-bits with linear 8-bits alpha. + * DEPTH24_STENCIL8 | 24-bits unsigned normalized integer depth, 8-bits stencil. + * DEPTH32F_STENCIL8| 32-bits floating-point depth, 8-bits stencil. + * + * + * Compressed texture formats + * -------------------------- + * + * Many compressed texture formats are supported as well, which include (but are not limited to) + * the following list: + * + * Name | Format + * :----------------|:-------------------------------------------------------------------------- + * EAC_R11 | Compresses R11UI + * EAC_R11_SIGNED | Compresses R11I + * EAC_RG11 | Compresses RG11UI + * EAC_RG11_SIGNED | Compresses RG11I + * ETC2_RGB8 | Compresses RGB8 + * ETC2_SRGB8 | compresses SRGB8 + * ETC2_EAC_RGBA8 | Compresses RGBA8 + * ETC2_EAC_SRGBA8 | Compresses SRGB8_A8 + * ETC2_RGB8_A1 | Compresses RGB8 with 1-bit alpha + * ETC2_SRGB8_A1 | Compresses sRGB8 with 1-bit alpha + * + * + * @see Texture + */ +enum class TextureFormat : uint16_t { + // 8-bits per element + R8, R8_SNORM, R8UI, R8I, STENCIL8, + + // 16-bits per element + R16F, R16UI, R16I, + RG8, RG8_SNORM, RG8UI, RG8I, + RGB565, + RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons. + RGB5_A1, + RGBA4, + DEPTH16, + + // 24-bits per element + RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, + DEPTH24, + + // 32-bits per element + R32F, R32UI, R32I, + RG16F, RG16UI, RG16I, + R11F_G11F_B10F, + RGBA8, SRGB8_A8,RGBA8_SNORM, + UNUSED, // used to be rgbm + RGB10_A2, RGBA8UI, RGBA8I, + DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8, + + // 48-bits per element + RGB16F, RGB16UI, RGB16I, + + // 64-bits per element + RG32F, RG32UI, RG32I, + RGBA16F, RGBA16UI, RGBA16I, + + // 96-bits per element + RGB32F, RGB32UI, RGB32I, + + // 128-bits per element + RGBA32F, RGBA32UI, RGBA32I, + + // compressed formats + + // Mandatory in GLES 3.0 and GL 4.3 + EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, + ETC2_RGB8, ETC2_SRGB8, + ETC2_RGB8_A1, ETC2_SRGB8_A1, + ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, + + // Available everywhere except Android/iOS + DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, + DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, + + // ASTC formats are available with a GLES extension + RGBA_ASTC_4x4, + RGBA_ASTC_5x4, + RGBA_ASTC_5x5, + RGBA_ASTC_6x5, + RGBA_ASTC_6x6, + RGBA_ASTC_8x5, + RGBA_ASTC_8x6, + RGBA_ASTC_8x8, + RGBA_ASTC_10x5, + RGBA_ASTC_10x6, + RGBA_ASTC_10x8, + RGBA_ASTC_10x10, + RGBA_ASTC_12x10, + RGBA_ASTC_12x12, + SRGB8_ALPHA8_ASTC_4x4, + SRGB8_ALPHA8_ASTC_5x4, + SRGB8_ALPHA8_ASTC_5x5, + SRGB8_ALPHA8_ASTC_6x5, + SRGB8_ALPHA8_ASTC_6x6, + SRGB8_ALPHA8_ASTC_8x5, + SRGB8_ALPHA8_ASTC_8x6, + SRGB8_ALPHA8_ASTC_8x8, + SRGB8_ALPHA8_ASTC_10x5, + SRGB8_ALPHA8_ASTC_10x6, + SRGB8_ALPHA8_ASTC_10x8, + SRGB8_ALPHA8_ASTC_10x10, + SRGB8_ALPHA8_ASTC_12x10, + SRGB8_ALPHA8_ASTC_12x12, + + // RGTC formats available with a GLES extension + RED_RGTC1, // BC4 unsigned + SIGNED_RED_RGTC1, // BC4 signed + RED_GREEN_RGTC2, // BC5 unsigned + SIGNED_RED_GREEN_RGTC2, // BC5 signed + + // BPTC formats available with a GLES extension + RGB_BPTC_SIGNED_FLOAT, // BC6H signed + RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned + RGBA_BPTC_UNORM, // BC7 + SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB +}; + +//! Bitmask describing the intended Texture Usage +enum class TextureUsage : uint8_t { + NONE = 0x00, + COLOR_ATTACHMENT = 0x01, //!< Texture can be used as a color attachment + DEPTH_ATTACHMENT = 0x02, //!< Texture can be used as a depth attachment + STENCIL_ATTACHMENT = 0x04, //!< Texture can be used as a stencil attachment + UPLOADABLE = 0x08, //!< Data can be uploaded into this texture (default) + SAMPLEABLE = 0x10, //!< Texture can be sampled (default) + SUBPASS_INPUT = 0x20, //!< Texture can be used as a subpass input + BLIT_SRC = 0x40, //!< Texture can be used the source of a blit() + BLIT_DST = 0x80, //!< Texture can be used the destination of a blit() + DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage +}; + +//! Texture swizzle +enum class TextureSwizzle : uint8_t { + SUBSTITUTE_ZERO, + SUBSTITUTE_ONE, + CHANNEL_0, + CHANNEL_1, + CHANNEL_2, + CHANNEL_3 +}; + +//! returns whether this format a depth format +static constexpr bool isDepthFormat(TextureFormat format) noexcept { + switch (format) { + case TextureFormat::DEPTH32F: + case TextureFormat::DEPTH24: + case TextureFormat::DEPTH16: + case TextureFormat::DEPTH32F_STENCIL8: + case TextureFormat::DEPTH24_STENCIL8: + return true; + default: + return false; + } +} + +static constexpr bool isStencilFormat(TextureFormat format) noexcept { + switch (format) { + case TextureFormat::STENCIL8: + case TextureFormat::DEPTH24_STENCIL8: + case TextureFormat::DEPTH32F_STENCIL8: + return true; + default: + return false; + } +} + +static constexpr bool isUnsignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8UI: + case TextureFormat::R16UI: + case TextureFormat::R32UI: + case TextureFormat::RG8UI: + case TextureFormat::RG16UI: + case TextureFormat::RG32UI: + case TextureFormat::RGB8UI: + case TextureFormat::RGB16UI: + case TextureFormat::RGB32UI: + case TextureFormat::RGBA8UI: + case TextureFormat::RGBA16UI: + case TextureFormat::RGBA32UI: + return true; + + default: + return false; + } +} + +static constexpr bool isSignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8I: + case TextureFormat::R16I: + case TextureFormat::R32I: + case TextureFormat::RG8I: + case TextureFormat::RG16I: + case TextureFormat::RG32I: + case TextureFormat::RGB8I: + case TextureFormat::RGB16I: + case TextureFormat::RGB32I: + case TextureFormat::RGBA8I: + case TextureFormat::RGBA16I: + case TextureFormat::RGBA32I: + return true; + + default: + return false; + } +} + +//! returns whether this format is a compressed format +static constexpr bool isCompressedFormat(TextureFormat format) noexcept { + return format >= TextureFormat::EAC_R11; +} + +//! returns whether this format is an ETC2 compressed format +static constexpr bool isETC2Compression(TextureFormat format) noexcept { + return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8; +} + +//! returns whether this format is an S3TC compressed format +static constexpr bool isS3TCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA; +} + +static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept { + return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA; +} + +//! returns whether this format is an RGTC compressed format +static constexpr bool isRGTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2; +} + +//! returns whether this format is an BPTC compressed format +static constexpr bool isBPTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM; +} + +static constexpr bool isASTCCompression(TextureFormat format) noexcept { + return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12; +} + +//! Texture Cubemap Face +enum class TextureCubemapFace : uint8_t { + // don't change the enums values + POSITIVE_X = 0, //!< +x face + NEGATIVE_X = 1, //!< -x face + POSITIVE_Y = 2, //!< +y face + NEGATIVE_Y = 3, //!< -y face + POSITIVE_Z = 4, //!< +z face + NEGATIVE_Z = 5, //!< -z face +}; + +//! Sampler Wrap mode +enum class SamplerWrapMode : uint8_t { + CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity. + REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction. + MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction. +}; + +//! Sampler minification filter +enum class SamplerMinFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. + NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs. + LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level. + NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs. + LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used. +}; + +//! Sampler magnification filter +enum class SamplerMagFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. +}; + +//! Sampler compare mode +enum class SamplerCompareMode : uint8_t { + // don't change the enums values + NONE = 0, + COMPARE_TO_TEXTURE = 1 +}; + +//! comparison function for the depth / stencil sampler +enum class SamplerCompareFunc : uint8_t { + // don't change the enums values + LE = 0, //!< Less or equal + GE, //!< Greater or equal + L, //!< Strictly less than + G, //!< Strictly greater than + E, //!< Equal + NE, //!< Not equal + A, //!< Always. Depth / stencil testing is deactivated. + N //!< Never. The depth / stencil test always fails. +}; + +//! Sampler parameters +struct SamplerParams { // NOLINT + SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST) + SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST) + SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE) + SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE) + + SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE) + uint8_t anisotropyLog2 : 3; //!< anisotropy level (0) + SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE) + uint8_t padding0 : 2; //!< reserved. must be 0. + + SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE) + uint8_t padding1 : 5; //!< reserved. must be 0. + uint8_t padding2 : 8; //!< reserved. must be 0. + + struct Hasher { + size_t operator()(SamplerParams p) const noexcept { + // we don't use std::hash<> here, so we don't have to include + return *reinterpret_cast(reinterpret_cast(&p)); + } + }; + + struct EqualTo { + bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + + struct LessThan { + bool operator()(SamplerParams lhs, SamplerParams rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + +private: + friend inline bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept { + return SamplerParams::LessThan{}(lhs, rhs); + } +}; +static_assert(sizeof(SamplerParams) == 4); + +// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code +// see android/.../TextureSampler.cpp +static_assert(sizeof(SamplerParams) <= sizeof(uint64_t), + "SamplerParams must be no more than 64 bits"); + +//! blending equation function +enum class BlendEquation : uint8_t { + ADD, //!< the fragment is added to the color buffer + SUBTRACT, //!< the fragment is subtracted from the color buffer + REVERSE_SUBTRACT, //!< the color buffer is subtracted from the fragment + MIN, //!< the min between the fragment and color buffer + MAX //!< the max between the fragment and color buffer +}; + +//! blending function +enum class BlendFunction : uint8_t { + ZERO, //!< f(src, dst) = 0 + ONE, //!< f(src, dst) = 1 + SRC_COLOR, //!< f(src, dst) = src + ONE_MINUS_SRC_COLOR, //!< f(src, dst) = 1-src + DST_COLOR, //!< f(src, dst) = dst + ONE_MINUS_DST_COLOR, //!< f(src, dst) = 1-dst + SRC_ALPHA, //!< f(src, dst) = src.a + ONE_MINUS_SRC_ALPHA, //!< f(src, dst) = 1-src.a + DST_ALPHA, //!< f(src, dst) = dst.a + ONE_MINUS_DST_ALPHA, //!< f(src, dst) = 1-dst.a + SRC_ALPHA_SATURATE //!< f(src, dst) = (1,1,1) * min(src.a, 1 - dst.a), 1 +}; + +//! stencil operation +enum class StencilOperation : uint8_t { + KEEP, //!< Keeps the current value. + ZERO, //!< Sets the value to 0. + REPLACE, //!< Sets the value to the stencil reference value. + INCR, //!< Increments the current value. Clamps to the maximum representable unsigned value. + INCR_WRAP, //!< Increments the current value. Wraps value to zero when incrementing the maximum representable unsigned value. + DECR, //!< Decrements the current value. Clamps to 0. + DECR_WRAP, //!< Decrements the current value. Wraps value to the maximum representable unsigned value when decrementing a value of zero. + INVERT, //!< Bitwise inverts the current value. +}; + +//! stencil faces +enum class StencilFace : uint8_t { + FRONT = 0x1, //!< Update stencil state for front-facing polygons. + BACK = 0x2, //!< Update stencil state for back-facing polygons. + FRONT_AND_BACK = FRONT | BACK, //!< Update stencil state for all polygons. +}; + +//! Stream for external textures +enum class StreamType { + NATIVE, //!< Not synchronized but copy-free. Good for video. + ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+. +}; + +//! Releases an ACQUIRED external texture, guaranteed to be called on the application thread. +using StreamCallback = void(*)(void* image, void* user); + +//! Vertex attribute descriptor +struct Attribute { + //! attribute is normalized (remapped between 0 and 1) + static constexpr uint8_t FLAG_NORMALIZED = 0x1; + //! attribute is an integer + static constexpr uint8_t FLAG_INTEGER_TARGET = 0x2; + static constexpr uint8_t BUFFER_UNUSED = 0xFF; + uint32_t offset = 0; //!< attribute offset in bytes + uint8_t stride = 0; //!< attribute stride in bytes + uint8_t buffer = BUFFER_UNUSED; //!< attribute buffer index + ElementType type = ElementType::BYTE; //!< attribute element type + uint8_t flags = 0x0; //!< attribute flags +}; + +using AttributeArray = std::array; + +//! Raster state descriptor +struct RasterState { + + using CullingMode = backend::CullingMode; + using DepthFunc = backend::SamplerCompareFunc; + using BlendEquation = backend::BlendEquation; + using BlendFunction = backend::BlendFunction; + + RasterState() noexcept { // NOLINT + static_assert(sizeof(RasterState) == sizeof(uint32_t), + "RasterState size not what was intended"); + culling = CullingMode::BACK; + blendEquationRGB = BlendEquation::ADD; + blendEquationAlpha = BlendEquation::ADD; + blendFunctionSrcRGB = BlendFunction::ONE; + blendFunctionSrcAlpha = BlendFunction::ONE; + blendFunctionDstRGB = BlendFunction::ZERO; + blendFunctionDstAlpha = BlendFunction::ZERO; + } + + bool operator == (RasterState rhs) const noexcept { return u == rhs.u; } + bool operator != (RasterState rhs) const noexcept { return u != rhs.u; } + + void disableBlending() noexcept { + blendEquationRGB = BlendEquation::ADD; + blendEquationAlpha = BlendEquation::ADD; + blendFunctionSrcRGB = BlendFunction::ONE; + blendFunctionSrcAlpha = BlendFunction::ONE; + blendFunctionDstRGB = BlendFunction::ZERO; + blendFunctionDstAlpha = BlendFunction::ZERO; + } + + // note: clang reduces this entire function to a simple load/mask/compare + bool hasBlending() const noexcept { + // This is used to decide if blending needs to be enabled in the h/w + return !(blendEquationRGB == BlendEquation::ADD && + blendEquationAlpha == BlendEquation::ADD && + blendFunctionSrcRGB == BlendFunction::ONE && + blendFunctionSrcAlpha == BlendFunction::ONE && + blendFunctionDstRGB == BlendFunction::ZERO && + blendFunctionDstAlpha == BlendFunction::ZERO); + } + + union { + struct { + //! culling mode + CullingMode culling : 2; // 2 + + //! blend equation for the red, green and blue components + BlendEquation blendEquationRGB : 3; // 5 + //! blend equation for the alpha component + BlendEquation blendEquationAlpha : 3; // 8 + + //! blending function for the source color + BlendFunction blendFunctionSrcRGB : 4; // 12 + //! blending function for the source alpha + BlendFunction blendFunctionSrcAlpha : 4; // 16 + //! blending function for the destination color + BlendFunction blendFunctionDstRGB : 4; // 20 + //! blending function for the destination alpha + BlendFunction blendFunctionDstAlpha : 4; // 24 + + //! Whether depth-buffer writes are enabled + bool depthWrite : 1; // 25 + //! Depth test function + DepthFunc depthFunc : 3; // 28 + + //! Whether color-buffer writes are enabled + bool colorWrite : 1; // 29 + + //! use alpha-channel as coverage mask for anti-aliasing + bool alphaToCoverage : 1; // 30 + + //! whether front face winding direction must be inverted + bool inverseFrontFaces : 1; // 31 + + //! padding, must be 0 + uint8_t padding : 1; // 32 + }; + uint32_t u = 0; + }; +}; + +/** + ********************************************************************************************** + * \privatesection + */ + +enum class ShaderStage : uint8_t { + VERTEX = 0, + FRAGMENT = 1, + COMPUTE = 2 +}; + +static constexpr size_t PIPELINE_STAGE_COUNT = 2; +enum class ShaderStageFlags : uint8_t { + NONE = 0, + VERTEX = 0x1, + FRAGMENT = 0x2, + COMPUTE = 0x4, + ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE +}; + +static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept { + switch (type) { + case ShaderStage::VERTEX: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX)); + case ShaderStage::FRAGMENT: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::FRAGMENT)); + case ShaderStage::COMPUTE: + return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::COMPUTE)); + } +} + +/** + * Selects which buffers to clear at the beginning of the render pass, as well as which buffers + * can be discarded at the beginning and end of the render pass. + * + */ +struct RenderPassFlags { + /** + * bitmask indicating which buffers to clear at the beginning of a render pass. + * This implies discard. + */ + TargetBufferFlags clear; + + /** + * bitmask indicating which buffers to discard at the beginning of a render pass. + * Discarded buffers have uninitialized content, they must be entirely drawn over or cleared. + */ + TargetBufferFlags discardStart; + + /** + * bitmask indicating which buffers to discard at the end of a render pass. + * Discarded buffers' content becomes invalid, they must not be read from again. + */ + TargetBufferFlags discardEnd; +}; + +/** + * Parameters of a render pass. + */ +struct RenderPassParams { + RenderPassFlags flags{}; //!< operations performed on the buffers for this pass + + Viewport viewport{}; //!< viewport for this pass + DepthRange depthRange{}; //!< depth range for this pass + + //! Color to use to clear the COLOR buffer. RenderPassFlags::clear must be set. + math::float4 clearColor = {}; + + //! Depth value to clear the depth buffer with + double clearDepth = 0.0; + + //! Stencil value to clear the stencil buffer with + uint32_t clearStencil = 0; + + /** + * The subpass mask specifies which color attachments are designated for read-back in the second + * subpass. If this is zero, the render pass has only one subpass. The least significant bit + * specifies that the first color attachment in the render target is a subpass input. + * + * For now only 2 subpasses are supported, so only the lower 8 bits are used, one for each color + * attachment (see MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT). + */ + uint16_t subpassMask = 0; + + /** + * This mask makes a promise to the backend about read-only usage of the depth attachment (bit + * 0) and the stencil attachment (bit 1). Some backends need to know if writes are disabled in + * order to allow sampling from the depth attachment. + */ + uint16_t readOnlyDepthStencil = 0; + + static constexpr uint16_t READONLY_DEPTH = 1 << 0; + static constexpr uint16_t READONLY_STENCIL = 1 << 1; +}; + +struct PolygonOffset { + float slope = 0; // factor in GL-speak + float constant = 0; // units in GL-speak +}; + +struct StencilState { + using StencilFunction = SamplerCompareFunc; + + struct StencilOperations { + //! Stencil test function + StencilFunction stencilFunc : 3; // 3 + + //! Stencil operation when stencil test fails + StencilOperation stencilOpStencilFail : 3; // 6 + + uint8_t padding0 : 2; // 8 + + //! Stencil operation when stencil test passes but depth test fails + StencilOperation stencilOpDepthFail : 3; // 11 + + //! Stencil operation when both stencil and depth test pass + StencilOperation stencilOpDepthStencilPass : 3; // 14 + + uint8_t padding1 : 2; // 16 + + //! Reference value for stencil comparison tests and updates + uint8_t ref; // 24 + + //! Masks the bits of the stencil values participating in the stencil comparison test. + uint8_t readMask; // 32 + + //! Masks the bits of the stencil values updated by the stencil test. + uint8_t writeMask; // 40 + }; + + //! Stencil operations for front-facing polygons + StencilOperations front = { + .stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff }; + + //! Stencil operations for back-facing polygons + StencilOperations back = { + .stencilFunc = StencilFunction::A, .ref = 0, .readMask = 0xff, .writeMask = 0xff }; + + //! Whether stencil-buffer writes are enabled + bool stencilWrite = false; + + uint8_t padding = 0; +}; + +static_assert(sizeof(StencilState::StencilOperations) == 5u, + "StencilOperations size not what was intended"); + +static_assert(sizeof(StencilState) == 12u, + "StencilState size not what was intended"); + +using FrameScheduledCallback = void(*)(PresentCallable callable, void* user); + +enum class Workaround : uint16_t { + // The EASU pass must split because shader compiler flattens early-exit branch + SPLIT_EASU, + // Backend allows feedback loop with ancillary buffers (depth/stencil) as long as they're + // read-only for the whole render pass. + ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP, + // for some uniform arrays, it's needed to do an initialization to avoid crash on adreno gpu + ADRENO_UNIFORM_ARRAY_CRASH, + // Workaround a Metal pipeline compilation error with the message: + // "Could not statically determine the target of a texture". See light_indirect.fs + A8X_STATIC_TEXTURE_TARGET_ERROR, + // Adreno drivers sometimes aren't able to blit into a layer of a texture array. + DISABLE_BLIT_INTO_TEXTURE_ARRAY, + // Multiple workarounds needed for PowerVR GPUs + POWER_VR_SHADER_WORKAROUNDS, + // The driver has some threads pinned, and we can't easily know on which core, it can hurt + // performance more if we end-up pinned on the same one. + DISABLE_THREAD_AFFINITY +}; + +//! The type of technique for stereoscopic rendering +enum class StereoscopicType : uint8_t { + // Stereoscopic rendering is performed using instanced rendering technique. + INSTANCED, + // Stereoscopic rendering is performed using the multiview feature from the graphics backend. + MULTIVIEW, +}; + +} // namespace filament::backend + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; +template<> struct utils::EnableIntegerOperators + : public std::true_type {}; +template<> struct utils::EnableIntegerOperators + : public std::true_type {}; + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::CullingMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ElementType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::Precision precision); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PrimitiveType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TargetBufferFlags f); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareFunc func); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMagFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMinFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerParams params); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerWrapMode wrap); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ShaderModel model); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureCubemapFace face); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferObjectBinding binding); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureSwizzle swizzle); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::AttributeArray& type); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PolygonOffset& po); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RasterState& rs); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RenderPassParams& b); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::Viewport& v); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ShaderStageFlags stageFlags); +#endif + +#endif // TNT_FILAMENT_BACKEND_DRIVERENUMS_H diff --git a/package/ios/libs/filament/include/backend/Handle.h b/package/ios/libs/filament/include/backend/Handle.h new file mode 100644 index 00000000..ffc16133 --- /dev/null +++ b/package/ios/libs/filament/include/backend/Handle.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_HANDLE_H +#define TNT_FILAMENT_BACKEND_HANDLE_H + +#if !defined(NDEBUG) +#include +#endif +#include + +#include // FIXME: STL headers are not allowed in public headers + +#include + +namespace filament::backend { + +struct HwBufferObject; +struct HwFence; +struct HwIndexBuffer; +struct HwProgram; +struct HwRenderPrimitive; +struct HwRenderTarget; +struct HwSamplerGroup; +struct HwStream; +struct HwSwapChain; +struct HwTexture; +struct HwTimerQuery; +struct HwVertexBuffer; + +/* + * A handle to a backend resource. HandleBase is for internal use only. + * HandleBase *must* be a trivial for the purposes of calls, that is, it cannot have user-defined + * copy or move constructors. + */ + +//! \privatesection + +class HandleBase { +public: + using HandleId = uint32_t; + static constexpr const HandleId nullid = HandleId{ UINT32_MAX }; + + constexpr HandleBase() noexcept: object(nullid) {} + + // whether this Handle is initialized + explicit operator bool() const noexcept { return object != nullid; } + + // clear the handle, this doesn't free associated resources + void clear() noexcept { object = nullid; } + + // get this handle's handleId + HandleId getId() const noexcept { return object; } + + // initialize a handle, for internal use only. + explicit HandleBase(HandleId id) noexcept : object(id) { + assert_invariant(object != nullid); // usually means an uninitialized handle is used + } + +protected: + HandleBase(HandleBase const& rhs) noexcept = default; + HandleBase& operator=(HandleBase const& rhs) noexcept = default; + +private: + HandleId object; +}; + +/** + * Type-safe handle to backend resources + * @tparam T Type of the resource + */ +template +struct Handle : public HandleBase { + + Handle() noexcept = default; + + Handle(Handle const& rhs) noexcept = default; + + Handle& operator=(Handle const& rhs) noexcept = default; + + explicit Handle(HandleId id) noexcept : HandleBase(id) { } + + // compare handles of the same type + bool operator==(const Handle& rhs) const noexcept { return getId() == rhs.getId(); } + bool operator!=(const Handle& rhs) const noexcept { return getId() != rhs.getId(); } + bool operator<(const Handle& rhs) const noexcept { return getId() < rhs.getId(); } + bool operator<=(const Handle& rhs) const noexcept { return getId() <= rhs.getId(); } + bool operator>(const Handle& rhs) const noexcept { return getId() > rhs.getId(); } + bool operator>=(const Handle& rhs) const noexcept { return getId() >= rhs.getId(); } + + // type-safe Handle cast + template::value> > + Handle(Handle const& base) noexcept : HandleBase(base) { } // NOLINT(hicpp-explicit-conversions,google-explicit-constructor) + +private: +#if !defined(NDEBUG) + template + friend utils::io::ostream& operator<<(utils::io::ostream& out, const Handle& h) noexcept; +#endif +}; + +// Types used by the command stream +// (we use this renaming because the macro-system doesn't deal well with "<" and ">") +using BufferObjectHandle = Handle; +using FenceHandle = Handle; +using IndexBufferHandle = Handle; +using ProgramHandle = Handle; +using RenderPrimitiveHandle = Handle; +using RenderTargetHandle = Handle; +using SamplerGroupHandle = Handle; +using StreamHandle = Handle; +using SwapChainHandle = Handle; +using TextureHandle = Handle; +using TimerQueryHandle = Handle; +using VertexBufferHandle = Handle; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_HANDLE_H diff --git a/package/ios/libs/filament/include/backend/PipelineState.h b/package/ios/libs/filament/include/backend/PipelineState.h new file mode 100644 index 00000000..aa98dda6 --- /dev/null +++ b/package/ios/libs/filament/include/backend/PipelineState.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PIPELINESTATE_H +#define TNT_FILAMENT_BACKEND_PIPELINESTATE_H + +#include +#include + +#include + +#include + +namespace filament::backend { + +//! \privatesection + +struct PipelineState { + Handle program; + RasterState rasterState; + StencilState stencilState; + PolygonOffset polygonOffset; + Viewport scissor{ 0, 0, (uint32_t)INT32_MAX, (uint32_t)INT32_MAX }; +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PipelineState& ps); +#endif + +#endif //TNT_FILAMENT_BACKEND_PIPELINESTATE_H diff --git a/package/ios/libs/filament/include/backend/PixelBufferDescriptor.h b/package/ios/libs/filament/include/backend/PixelBufferDescriptor.h new file mode 100644 index 00000000..c45f344d --- /dev/null +++ b/package/ios/libs/filament/include/backend/PixelBufferDescriptor.h @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H + +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +/** + * A descriptor to an image in main memory, typically used to transfer image data from the CPU + * to the GPU. + * + * A PixelBufferDescriptor owns the memory buffer it references, therefore PixelBufferDescriptor + * cannot be copied, but can be moved. + * + * PixelBufferDescriptor releases ownership of the memory-buffer when it's destroyed. + */ +class UTILS_PUBLIC PixelBufferDescriptor : public BufferDescriptor { +public: + using PixelDataFormat = backend::PixelDataFormat; + using PixelDataType = backend::PixelDataType; + + PixelBufferDescriptor() = default; + + /** + * Creates a new PixelBufferDescriptor referencing an image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param alignment Alignment in bytes of pixel rows + * @param left Left coordinate in pixels + * @param top Top coordinate in pixels + * @param stride Stride of a row in pixels + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + left(left), top(top), stride(stride), + format(format), type(type), alignment(alignment) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment = 1, + uint32_t left = 0, uint32_t top = 0, uint32_t stride = 0, + Callback callback = nullptr, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + left(left), top(top), stride(stride), + format(format), type(type), alignment(alignment) { + } + + /** + * Creates a new PixelBufferDescriptor referencing an image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + stride(0), format(format), type(type), alignment(1) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, + Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + stride(0), format(format), type(type), alignment(1) { + } + + + /** + * Creates a new PixelBufferDescriptor referencing a compressed image in main memory + * + * @param buffer Virtual address of the buffer containing the image + * @param size Size in bytes of the buffer containing the image + * @param format Compressed format of the image + * @param imageSize Compressed size of the image + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback A callback used to release the CPU buffer + * @param user An opaque user pointer passed to the callback function when it's called + */ + PixelBufferDescriptor(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, + CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, handler, callback, user), + imageSize(imageSize), compressedFormat(format), type(PixelDataType::COMPRESSED), + alignment(1) { + } + + PixelBufferDescriptor(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, + Callback callback, void* user = nullptr) noexcept + : BufferDescriptor(buffer, size, callback, user), + imageSize(imageSize), compressedFormat(format), type(PixelDataType::COMPRESSED), + alignment(1) { + } + + // -------------------------------------------------------------------------------------------- + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T* data, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, imageSize, handler, [](void* b, size_t s, void* u) { + (static_cast(u)->*method)(b, s); }, data + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, type, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T&& functor, + CallbackHandler* handler = nullptr) noexcept { + return { buffer, size, format, imageSize, + handler, [](void* b, size_t s, void* u) { + T* const that = static_cast(u); + that->operator()(b, s); + delete that; + }, new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + + /** + * Computes the size in bytes needed to fit an image of given dimensions and format + * + * @param format Format of the image pixels + * @param type Type of the image pixels + * @param stride Stride of a row in pixels + * @param height Height of the image in rows + * @param alignment Alignment in bytes of pixel rows + * @return The buffer size needed to fit this image in bytes + */ + static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type, + size_t stride, size_t height, size_t alignment) noexcept { + assert_invariant(alignment); + + if (type == PixelDataType::COMPRESSED) { + return 0; + } + + size_t n = 0; + switch (format) { + case PixelDataFormat::R: + case PixelDataFormat::R_INTEGER: + case PixelDataFormat::DEPTH_COMPONENT: + case PixelDataFormat::ALPHA: + n = 1; + break; + case PixelDataFormat::RG: + case PixelDataFormat::RG_INTEGER: + case PixelDataFormat::DEPTH_STENCIL: + n = 2; + break; + case PixelDataFormat::RGB: + case PixelDataFormat::RGB_INTEGER: + n = 3; + break; + case PixelDataFormat::UNUSED: // shouldn't happen (used to be rgbm) + case PixelDataFormat::RGBA: + case PixelDataFormat::RGBA_INTEGER: + n = 4; + break; + } + + size_t bpp = n; + switch (type) { + case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings + case PixelDataType::UBYTE: + case PixelDataType::BYTE: + // nothing to do + break; + case PixelDataType::USHORT: + case PixelDataType::SHORT: + case PixelDataType::HALF: + bpp *= 2; + break; + case PixelDataType::UINT: + case PixelDataType::INT: + case PixelDataType::FLOAT: + bpp *= 4; + break; + case PixelDataType::UINT_10F_11F_11F_REV: + // Special case, format must be RGB and uses 4 bytes + assert_invariant(format == PixelDataFormat::RGB); + bpp = 4; + break; + case PixelDataType::UINT_2_10_10_10_REV: + // Special case, format must be RGBA and uses 4 bytes + assert_invariant(format == PixelDataFormat::RGBA); + bpp = 4; + break; + case PixelDataType::USHORT_565: + // Special case, format must be RGB and uses 2 bytes + assert_invariant(format == PixelDataFormat::RGB); + bpp = 2; + break; + } + + size_t const bpr = bpp * stride; + size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1); + return bprAligned * height; + } + + //! left coordinate in pixels + uint32_t left = 0; + //! top coordinate in pixels + uint32_t top = 0; + union { + struct { + //! stride in pixels + uint32_t stride; + //! Pixel data format + PixelDataFormat format; + }; + struct { + //! compressed image size + uint32_t imageSize; + //! compressed image format + backend::CompressedPixelDataType compressedFormat; + }; + }; + //! pixel data type + PixelDataType type : 4; + //! row alignment in bytes + uint8_t alignment : 4; +}; + +} // namespace backend::filament + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PixelBufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H diff --git a/package/ios/libs/filament/include/backend/Platform.h b/package/ios/libs/filament/include/backend/Platform.h new file mode 100644 index 00000000..b89fb98f --- /dev/null +++ b/package/ios/libs/filament/include/backend/Platform.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PLATFORM_H +#define TNT_FILAMENT_BACKEND_PLATFORM_H + +#include +#include + +#include + +namespace filament::backend { + +class Driver; + +/** + * Platform is an interface that abstracts how the backend (also referred to as Driver) is + * created. The backend provides several common Platform concrete implementations, which are + * selected automatically. It is possible however to provide a custom Platform when creating + * the filament Engine. + */ +class UTILS_PUBLIC Platform { +public: + struct SwapChain {}; + struct Fence {}; + struct Stream {}; + + struct DriverConfig { + /** + * Size of handle arena in bytes. Setting to 0 indicates default value is to be used. + * Driver clamps to valid values. + */ + size_t handleArenaSize = 0; + + /** + * This number of most-recently destroyed textures will be tracked for use-after-free. + * Throws an exception when a texture is freed but still bound to a SamplerGroup and used in + * a draw call. 0 disables completely. Currently only respected by the Metal backend. + */ + size_t textureUseAfterFreePoolSize = 0; + + /** + * Set to `true` to forcibly disable parallel shader compilation in the backend. + * Currently only honored by the GL backend. + */ + bool disableParallelShaderCompile = false; + }; + + Platform() noexcept; + + virtual ~Platform() noexcept; + + /** + * Queries the underlying OS version. + * @return The OS version. + */ + virtual int getOSVersion() const noexcept = 0; + + /** + * Creates and initializes the low-level API (e.g. an OpenGL context or Vulkan instance), + * then creates the concrete Driver. + * The caller takes ownership of the returned Driver* and must destroy it with delete. + * + * @param sharedContext an optional shared context. This is not meaningful with all graphic + * APIs and platforms. + * For EGL platforms, this is an EGLContext. + * + * @param driverConfig specifies driver initialization parameters + * + * @return nullptr on failure, or a pointer to the newly created driver. + */ + virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, + const DriverConfig& driverConfig) noexcept = 0; + + /** + * Processes the platform's event queue when called from its primary event-handling thread. + * + * Internally, Filament might need to call this when waiting on a fence. It is only implemented + * on platforms that need it, such as macOS + OpenGL. Returns false if this is not the main + * thread, or if the platform does not need to perform any special processing. + */ + virtual bool pumpEvents() noexcept; + + /** + * InsertBlobFunc is an Invocable to an application-provided function that a + * backend implementation may use to insert a key/value pair into the + * cache. + */ + using InsertBlobFunc = utils::Invocable< + void(const void* UTILS_NONNULL key, size_t keySize, + const void* UTILS_NONNULL value, size_t valueSize)>; + + /* + * RetrieveBlobFunc is an Invocable to an application-provided function that a + * backend implementation may use to retrieve a cached value from the + * cache. + */ + using RetrieveBlobFunc = utils::Invocable< + size_t(const void* UTILS_NONNULL key, size_t keySize, + void* UTILS_NONNULL value, size_t valueSize)>; + + /** + * Sets the callback functions that the backend can use to interact with caching functionality + * provided by the application. + * + * Cache functions may only be specified once during the lifetime of a + * Platform. The and Invocables may be called at any time and + * from any thread from the time at which setBlobFunc is called until the time that Platform + * is destroyed. Concurrent calls to these functions from different threads is also allowed. + * Either function can be null. + * + * @param insertBlob an Invocable that inserts a new value into the cache and associates + * it with the given key + * @param retrieveBlob an Invocable that retrieves from the cache the value associated with a + * given key + */ + void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept; + + /** + * @return true if insertBlob is valid. + */ + bool hasInsertBlobFunc() const noexcept; + + /** + * @return true if retrieveBlob is valid. + */ + bool hasRetrieveBlobFunc() const noexcept; + + /** + * @return true if either of insertBlob or retrieveBlob are valid. + */ + bool hasBlobFunc() const noexcept { + return hasInsertBlobFunc() || hasRetrieveBlobFunc(); + } + + /** + * To insert a new binary value into the cache and associate it with a given + * key, the backend implementation can call the application-provided callback + * function insertBlob. + * + * No guarantees are made as to whether a given key/value pair is present in + * the cache after the set call. If a different value has been associated + * with the given key in the past then it is undefined which value, if any, is + * associated with the key after the set call. Note that while there are no + * guarantees, the cache implementation should attempt to cache the most + * recently set value for a given key. + * + * @param key pointer to the beginning of the key data that is to be inserted + * @param keySize specifies the size in byte of the data pointed to by + * @param value pointer to the beginning of the value data that is to be inserted + * @param valueSize specifies the size in byte of the data pointed to by + */ + void insertBlob(const void* UTILS_NONNULL key, size_t keySize, + const void* UTILS_NONNULL value, size_t valueSize); + + /** + * To retrieve the binary value associated with a given key from the cache, a + * the backend implementation can call the application-provided callback + * function retrieveBlob. + * + * If the cache contains a value for the given key and its size in bytes is + * less than or equal to then the value is written to the memory + * pointed to by . Otherwise nothing is written to the memory pointed + * to by . + * + * @param key pointer to the beginning of the key + * @param keySize specifies the size in bytes of the binary key pointed to by + * @param value pointer to a buffer to receive the cached binary data, if it exists + * @param valueSize specifies the size in bytes of the memory pointed to by + * @return If the cache contains a value associated with the given key then the + * size of that binary value in bytes is returned. Otherwise 0 is returned. + */ + size_t retrieveBlob(const void* UTILS_NONNULL key, size_t keySize, + void* UTILS_NONNULL value, size_t valueSize); + +private: + InsertBlobFunc mInsertBlob; + RetrieveBlobFunc mRetrieveBlob; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BACKEND_PLATFORM_H diff --git a/package/ios/libs/filament/include/backend/PresentCallable.h b/package/ios/libs/filament/include/backend/PresentCallable.h new file mode 100644 index 00000000..4402f222 --- /dev/null +++ b/package/ios/libs/filament/include/backend/PresentCallable.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_PRESENTCALLABLE +#define TNT_FILAMENT_BACKEND_PRESENTCALLABLE + +#include + +namespace filament::backend { + +/** + * A PresentCallable is a callable object that, when called, schedules a frame for presentation on + * a SwapChain. + * + * Typically, Filament's backend is responsible scheduling a frame's presentation. However, there + * are certain cases where the application might want to control when a frame is scheduled for + * presentation. + * + * For example, on iOS, UIKit elements can be synchronized to 3D content by scheduling a present + * within a CATransation: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void myFrameScheduledCallback(PresentCallable presentCallable, void* user) { + * [CATransaction begin]; + * // Update other UI elements... + * presentCallable(); + * [CATransaction commit]; + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To obtain a PresentCallable, set a SwapChain::FrameScheduledCallback on a SwapChain with the + * SwapChain::setFrameScheduledCallback method. The callback is called with a PresentCallable object + * and optional user data: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * swapChain->setFrameScheduledCallback(myFrameScheduledCallback, nullptr); + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other + * backends ignore the callback (which will never be called) and proceed normally. + * + * @remark The SwapChain::FrameScheduledCallback is called on an arbitrary thread. + * + * Applications *must* call each PresentCallable they receive. Each PresentCallable represents a + * frame that is waiting to be presented. If an application fails to call a PresentCallable, a + * memory leak could occur. To "cancel" the presentation of a frame, pass false to the + * PresentCallable, which will cancel the presentation of the frame and release associated memory. + * + * @see Renderer, SwapChain::setFrameScheduledCallback + */ +class UTILS_PUBLIC PresentCallable { +public: + + using PresentFn = void(*)(bool presentFrame, void* user); + + PresentCallable(PresentFn fn, void* user) noexcept; + ~PresentCallable() noexcept = default; + PresentCallable(const PresentCallable& rhs) = default; + PresentCallable& operator=(const PresentCallable& rhs) = default; + + /** + * Call this PresentCallable, scheduling the associated frame for presentation. Pass false for + * presentFrame to effectively "cancel" the presentation of the frame. + * + * @param presentFrame if false, will not present the frame but releases associated memory + */ + void operator()(bool presentFrame = true) noexcept; + +private: + + PresentFn mPresentFn; + void* mUser = nullptr; + +}; + +/** + * @deprecated, FrameFinishedCallback has been renamed to SwapChain::FrameScheduledCallback. + */ +using FrameFinishedCallback UTILS_DEPRECATED = void(*)(PresentCallable callable, void* user); + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRESENTCALLABLE diff --git a/package/ios/libs/filament/include/backend/Program.h b/package/ios/libs/filament/include/backend/Program.h new file mode 100644 index 00000000..97deb6c5 --- /dev/null +++ b/package/ios/libs/filament/include/backend/Program.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H +#define TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H + +#include +#include +#include +#include + +#include + +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers +#include // FIXME: STL headers are not allowed in public headers + +#include +#include + +namespace filament::backend { + +class Program { +public: + + static constexpr size_t SHADER_TYPE_COUNT = 3; + static constexpr size_t UNIFORM_BINDING_COUNT = CONFIG_UNIFORM_BINDING_COUNT; + static constexpr size_t SAMPLER_BINDING_COUNT = CONFIG_SAMPLER_BINDING_COUNT; + + struct Sampler { + utils::CString name = {}; // name of the sampler in the shader + uint32_t binding = 0; // binding point of the sampler in the shader + }; + + struct SamplerGroupData { + utils::FixedCapacityVector samplers; + ShaderStageFlags stageFlags = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS; + }; + + struct Uniform { + utils::CString name; // full qualified name of the uniform field + uint16_t offset; // offset in 'uint32_t' into the uniform buffer + uint8_t size; // >1 for arrays + UniformType type; // uniform type + }; + + using UniformBlockInfo = std::array; + using UniformInfo = utils::FixedCapacityVector; + using SamplerGroupInfo = std::array; + using ShaderBlob = utils::FixedCapacityVector; + using ShaderSource = std::array; + + Program() noexcept; + + Program(const Program& rhs) = delete; + Program& operator=(const Program& rhs) = delete; + + Program(Program&& rhs) noexcept; + Program& operator=(Program&& rhs) noexcept = delete; + + ~Program() noexcept; + + Program& priorityQueue(CompilerPriorityQueue priorityQueue) noexcept; + + // sets the material name and variant for diagnostic purposes only + Program& diagnostics(utils::CString const& name, + utils::Invocable&& 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(ShaderStage shader, void const* data, size_t size); + + // Note: This is only needed for GLES3.0 backends, because the layout(binding=) syntax is + // not permitted in glsl. The backend needs a way to associate a uniform block + // to a binding point. + Program& uniformBlockBindings( + utils::FixedCapacityVector> const& uniformBlockBindings) noexcept; + + // Note: This is only needed for GLES2.0, this is used to emulate UBO. This function tells + // the program everything it needs to know about the uniforms at a given binding + Program& uniforms(uint32_t index, UniformInfo const& uniforms) noexcept; + + // Note: This is only needed for GLES2.0. + Program& attributes( + utils::FixedCapacityVector> attributes) noexcept; + + // sets the 'bindingPoint' sampler group descriptor for this program. + // 'samplers' can be destroyed after this call. + // This effectively associates a set of (BindingPoints, index) to a texture unit in the shader. + // Or more precisely, what layout(binding=) is set to in GLSL. + Program& setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFlags, + Sampler const* samplers, size_t count) noexcept; + + struct SpecializationConstant { + using Type = std::variant; + uint32_t id; // id set in glsl + Type value; // value and type + }; + + Program& specializationConstants( + utils::FixedCapacityVector specConstants) noexcept; + + Program& cacheId(uint64_t cacheId) noexcept; + + ShaderSource const& getShadersSource() const noexcept { return mShadersSource; } + ShaderSource& getShadersSource() noexcept { return mShadersSource; } + + UniformBlockInfo const& getUniformBlockBindings() const noexcept { return mUniformBlocks; } + UniformBlockInfo& getUniformBlockBindings() noexcept { return mUniformBlocks; } + + SamplerGroupInfo const& getSamplerGroupInfo() const { return mSamplerGroups; } + SamplerGroupInfo& getSamplerGroupInfo() { return mSamplerGroups; } + + auto const& getBindingUniformInfo() const { return mBindingUniformInfo; } + auto& getBindingUniformInfo() { return mBindingUniformInfo; } + + auto const& getAttributes() const { return mAttributes; } + auto& getAttributes() { return mAttributes; } + + utils::CString const& getName() const noexcept { return mName; } + utils::CString& getName() noexcept { return mName; } + + utils::FixedCapacityVector const& getSpecializationConstants() const noexcept { + return mSpecializationConstants; + } + utils::FixedCapacityVector& getSpecializationConstants() noexcept { + return mSpecializationConstants; + } + + uint64_t getCacheId() const noexcept { return mCacheId; } + + CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; } + +private: + friend utils::io::ostream& operator<<(utils::io::ostream& out, const Program& builder); + + UniformBlockInfo mUniformBlocks = {}; + SamplerGroupInfo mSamplerGroups = {}; + ShaderSource mShadersSource; + utils::CString mName; + uint64_t mCacheId{}; + utils::Invocable mLogger; + utils::FixedCapacityVector mSpecializationConstants; + utils::FixedCapacityVector> mAttributes; + std::array mBindingUniformInfo; + CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_PROGRAM_H diff --git a/package/ios/libs/filament/include/backend/README.md b/package/ios/libs/filament/include/backend/README.md new file mode 100644 index 00000000..02268268 --- /dev/null +++ b/package/ios/libs/filament/include/backend/README.md @@ -0,0 +1,4 @@ +# include/backend Headers + +Headers in `include/backend/` are fully public, in particular they can be included in filament's +public headers. diff --git a/package/ios/libs/filament/include/backend/SamplerDescriptor.h b/package/ios/libs/filament/include/backend/SamplerDescriptor.h new file mode 100644 index 00000000..f99472da --- /dev/null +++ b/package/ios/libs/filament/include/backend/SamplerDescriptor.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H + +#include +#include + +#include + +namespace filament::backend { + +struct UTILS_PUBLIC SamplerDescriptor { + Handle t; + SamplerParams s{}; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_SAMPLERDESCRIPTOR_H diff --git a/package/ios/libs/filament/include/backend/TargetBufferInfo.h b/package/ios/libs/filament/include/backend/TargetBufferInfo.h new file mode 100644 index 00000000..0f318d6e --- /dev/null +++ b/package/ios/libs/filament/include/backend/TargetBufferInfo.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H +#define TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H + +#include + +#include + +#include +#include + +namespace filament::backend { + +//! \privatesection + +struct TargetBufferInfo { + // texture to be used as render target + Handle handle; + + // level to be used + uint8_t level = 0; + + // for cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping + uint16_t layer = 0; +}; + +class MRT { +public: + static constexpr uint8_t MIN_SUPPORTED_RENDER_TARGET_COUNT = 4u; + + // When updating this, make sure to also take care of RenderTarget.java + static constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u; + +private: + TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT]; + +public: + TargetBufferInfo const& operator[](size_t i) const noexcept { + return mInfos[i]; + } + + TargetBufferInfo& operator[](size_t i) noexcept { + return mInfos[i]; + } + + MRT() noexcept = default; + + MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions) + : mInfos{ color } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1) noexcept + : mInfos{ color0, color1 } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1, + TargetBufferInfo const& color2) noexcept + : mInfos{ color0, color1, color2 } { + } + + MRT(TargetBufferInfo const& color0, TargetBufferInfo const& color1, + TargetBufferInfo const& color2, TargetBufferInfo const& color3) noexcept + : mInfos{ color0, color1, color2, color3 } { + } + + // this is here for backward compatibility + MRT(Handle handle, uint8_t level, uint16_t layer) noexcept + : mInfos{{ handle, level, layer }} { + } +}; + +} // namespace filament::backend + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::TargetBufferInfo& tbi); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::MRT& mrt); +#endif + +#endif //TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H diff --git a/package/ios/libs/filament/include/backend/platforms/OpenGLPlatform.h b/package/ios/libs/filament/include/backend/platforms/OpenGLPlatform.h new file mode 100644 index 00000000..12deb801 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/OpenGLPlatform.h @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H +#define TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H + +#include +#include +#include + +#include + +#include + +namespace filament::backend { + +class Driver; + +/** + * A Platform interface that creates an OpenGL backend. + * + * WARNING: None of the methods below are allowed to change the GL state and must restore it + * upon return. + * + */ +class OpenGLPlatform : public Platform { +protected: + + /* + * Derived classes can use this to instantiate the default OpenGLDriver backend. + * This is typically called from your implementation of createDriver() + */ + static Driver* UTILS_NULLABLE createDefaultDriver(OpenGLPlatform* UTILS_NONNULL platform, + void* UTILS_NULLABLE sharedContext, const DriverConfig& driverConfig); + + ~OpenGLPlatform() noexcept override; + +public: + + struct ExternalTexture { + unsigned int target; // GLenum target + unsigned int id; // GLuint id + }; + + /** + * Called by the driver to destroy the OpenGL context. This should clean up any windows + * or buffers from initialization. This is for instance where `eglDestroyContext` would be + * called. + */ + virtual void terminate() noexcept = 0; + + /** + * Called by the driver to create a SwapChain for this driver. + * + * @param nativeWindow a token representing the native window. See concrete implementation + * for details. + * @param flags extra flags used by the implementation, see filament::SwapChain + * @return The driver's SwapChain object. + * + */ + virtual SwapChain* UTILS_NONNULL createSwapChain( + void* UTILS_NULLABLE nativeWindow, uint64_t flags) noexcept = 0; + + /** + * Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag. + * The default implementation returns false. + * + * @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise. + */ + virtual bool isSRGBSwapChainSupported() const noexcept; + + /** + * Called by the driver create a headless SwapChain. + * + * @param width width of the buffer + * @param height height of the buffer + * @param flags extra flags used by the implementation, see filament::SwapChain + * @return The driver's SwapChain object. + * + * TODO: we need a more generic way of passing construction parameters + * A void* might be enough. + */ + virtual SwapChain* UTILS_NULLABLE createSwapChain( + uint32_t width, uint32_t height, uint64_t flags) noexcept = 0; + + /** + * Called by the driver to destroys the SwapChain + * @param swapChain SwapChain to be destroyed. + */ + virtual void destroySwapChain(SwapChain* UTILS_NONNULL swapChain) noexcept = 0; + + /** + * Returns the set of buffers that must be preserved up to the call to commit(). + * The default value is TargetBufferFlags::NONE. + * The color buffer is always preserved, however ancillary buffers, such as the depth buffer + * are generally discarded. The preserve flags can be used to make sure those ancillary + * buffers are preserved until the call to commit. + * + * @param swapChain + * @return buffer that must be preserved + * @see commit() + */ + virtual TargetBufferFlags getPreservedFlags(SwapChain* UTILS_NONNULL swapChain) noexcept; + + /** + * Called by the driver to establish the default FBO. The default implementation returns 0. + * @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object. + */ + virtual uint32_t createDefaultRenderTarget() noexcept; + + /** + * Called by the driver to make the OpenGL context active on the calling thread and bind + * the drawSwapChain to the default render target (FBO) created with createDefaultRenderTarget. + * @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO. + * @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`) + */ + virtual void makeCurrent( + SwapChain* UTILS_NONNULL drawSwapChain, + SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0; + + /** + * Called by the driver once the current frame finishes drawing. Typically, this should present + * the drawSwapChain. This is for example where `eglMakeCurrent()` would be called. + * @param swapChain the SwapChain to present. + */ + virtual void commit(SwapChain* UTILS_NONNULL swapChain) noexcept = 0; + + /** + * Set the time the next committed buffer should be presented to the user at. + * + * @param presentationTimeInNanosecond time in the future in nanosecond. The clock used depends + * on the concrete platform implementation. + */ + virtual void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept; + + // -------------------------------------------------------------------------------------------- + // Fence support + + /** + * Can this implementation create a Fence. + * @return true if supported, false otherwise. The default implementation returns false. + */ + virtual bool canCreateFence() noexcept; + + /** + * Creates a Fence (e.g. eglCreateSyncKHR). This must be implemented if `canCreateFence` + * returns true. Fences are used for frame pacing. + * + * @return A Fence object. The default implementation returns nullptr. + */ + virtual Fence* UTILS_NULLABLE createFence() noexcept; + + /** + * Destroys a Fence object. The default implementation does nothing. + * + * @param fence Fence to destroy. + */ + virtual void destroyFence(Fence* UTILS_NONNULL fence) noexcept; + + /** + * Waits on a Fence. + * + * @param fence Fence to wait on. + * @param timeout Timeout. + * @return Whether the fence signaled or timed out. See backend::FenceStatus. + * The default implementation always return backend::FenceStatus::ERROR. + */ + virtual backend::FenceStatus waitFence(Fence* UTILS_NONNULL fence, uint64_t timeout) noexcept; + + + // -------------------------------------------------------------------------------------------- + // Streaming support + + /** + * Creates a Stream from a native Stream. + * + * WARNING: This is called synchronously from the application thread (NOT the Driver thread) + * + * @param nativeStream The native stream, this parameter depends on the concrete implementation. + * @return A new Stream object. + */ + virtual Stream* UTILS_NULLABLE createStream(void* UTILS_NULLABLE nativeStream) noexcept; + + /** + * Destroys a Stream. + * @param stream Stream to destroy. + */ + virtual void destroyStream(Stream* UTILS_NONNULL stream) noexcept; + + /** + * The specified stream takes ownership of the texture (tname) object + * Once attached, the texture is automatically updated with the Stream's content, which + * could be a video stream for instance. + * + * @param stream Stream to take ownership of the texture + * @param tname GL texture id to "bind" to the Stream. + */ + virtual void attach(Stream* UTILS_NONNULL stream, intptr_t tname) noexcept; + + /** + * Destroys the texture associated to the stream + * @param stream Stream to detach from its texture + */ + virtual void detach(Stream* UTILS_NONNULL stream) noexcept; + + /** + * Updates the content of the texture attached to the stream. + * @param stream Stream to update + * @param timestamp Output parameter: Timestamp of the image bound to the texture. + */ + virtual void updateTexImage(Stream* UTILS_NONNULL stream, + int64_t* UTILS_NONNULL timestamp) noexcept; + + + // -------------------------------------------------------------------------------------------- + // External Image support + + /** + * Creates an external texture handle. External textures don't have any parameters because + * these are undefined until setExternalImage() is called. + * @return a pointer to an ExternalTexture structure filled with valid token. However, the + * implementation could just return { 0, GL_TEXTURE_2D } at this point. The actual + * values can be delayed until setExternalImage. + */ + virtual ExternalTexture* UTILS_NULLABLE createExternalImageTexture() noexcept; + + /** + * Destroys an external texture handle and associated data. + * @param texture a pointer to the handle to destroy. + */ + virtual void destroyExternalImage(ExternalTexture* UTILS_NONNULL texture) noexcept; + + // called on the application thread to allow Filament to take ownership of the image + + /** + * Takes ownership of the externalImage. The externalImage parameter depends on the Platform's + * concrete implementation. Ownership is released when destroyExternalImage() is called. + * + * WARNING: This is called synchronously from the application thread (NOT the Driver thread) + * + * @param externalImage A token representing the platform's external image. + * @see destroyExternalImage + */ + virtual void retainExternalImage(void* UTILS_NONNULL externalImage) noexcept; + + /** + * Called to bind the platform-specific externalImage to an ExternalTexture. + * ExternalTexture::id is guaranteed to be bound when this method is called and ExternalTexture + * is updated with new values for id/target if necessary. + * + * WARNING: this method is not allowed to change the bound texture, or must restore the previous + * binding upon return. This is to avoid problem with a backend doing state caching. + * + * @param externalImage The platform-specific external image. + * @param texture an in/out pointer to ExternalTexture, id and target can be updated if necessary. + * @return true on success, false on error. + */ + virtual bool setExternalImage(void* UTILS_NONNULL externalImage, + ExternalTexture* UTILS_NONNULL texture) noexcept; + + /** + * The method allows platforms to convert a user-supplied external image object into a new type + * (e.g. HardwareBuffer => EGLImage). The default implementation returns source. + * @param source Image to transform. + * @return Transformed image. + */ + virtual AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept; + + // -------------------------------------------------------------------------------------------- + + /** + * Returns true if additional OpenGL contexts can be created. Default: false. + * @return true if additional OpenGL contexts can be created. + * @see createContext + */ + virtual bool isExtraContextSupported() const noexcept; + + /** + * Creates an OpenGL context with the same configuration than the main context and makes it + * current to the current thread. Must not be called from the main driver thread. + * createContext() is only supported if isExtraContextSupported() returns true. + * These additional contexts will be automatically terminated in terminate. + * + * @param shared whether the new context is shared with the main context. + * @see isExtraContextSupported() + * @see terminate() + */ + virtual void createContext(bool shared); + + /** + * Detach and destroy the current context if any and releases all resources associated to + * this thread. + */ + virtual void releaseContext() noexcept; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BACKEND_PRIVATE_OPENGLPLATFORM_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformCocoaGL.h b/package/ios/libs/filament/include/backend/platforms/PlatformCocoaGL.h new file mode 100644 index 00000000..72a12185 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformCocoaGL.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H + +#include +#include + +#include + +namespace filament::backend { + +struct PlatformCocoaGLImpl; + +/** + * A concrete implementation of OpenGLPlatform that supports macOS's Cocoa. + */ +class PlatformCocoaGL : public OpenGLPlatform { +public: + PlatformCocoaGL(); + ~PlatformCocoaGL() noexcept override; + +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + // Currently returns 0 + int getOSVersion() const noexcept override; + + bool pumpEvents() noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + void retainExternalImage(void* externalImage) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + +private: + PlatformCocoaGLImpl* pImpl = nullptr; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h b/package/ios/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h new file mode 100644 index 00000000..a60a6369 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformCocoaTouchGL.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H + +#include + +#include + +#include + +namespace filament::backend { + +struct PlatformCocoaTouchGLImpl; + +class PlatformCocoaTouchGL : public OpenGLPlatform { +public: + PlatformCocoaTouchGL(); + ~PlatformCocoaTouchGL() noexcept override; + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + uint32_t createDefaultRenderTarget() noexcept override; + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + void retainExternalImage(void* externalImage) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + +private: + PlatformCocoaTouchGLImpl* pImpl = nullptr; +}; + +using ContextManager = PlatformCocoaTouchGL; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_TOUCH_GL_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformEGL.h b/package/ios/libs/filament/include/backend/platforms/PlatformEGL.h new file mode 100644 index 00000000..cb124665 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformEGL.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports EGL. + */ +class PlatformEGL : public OpenGLPlatform { +public: + + PlatformEGL() noexcept; + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + void releaseContext() noexcept override; + + // Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default. + virtual bool isOpenGL() const noexcept; + +protected: + + // -------------------------------------------------------------------------------------------- + // Helper for EGL configs and attributes parameters + + class Config { + public: + Config(); + Config(std::initializer_list> list); + EGLint& operator[](EGLint name); + EGLint operator[](EGLint name) const; + void erase(EGLint name) noexcept; + EGLint const* data() const noexcept { + return reinterpret_cast(mConfig.data()); + } + size_t size() const noexcept { + return mConfig.size(); + } + private: + std::vector> mConfig = {{ EGL_NONE, EGL_NONE }}; + }; + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + /** + * Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation + * that supports OpenGL/OpenGL ES. + */ + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + /** + * This returns zero. This method can be overridden to return something more useful. + * @return zero + */ + int getOSVersion() const noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + bool isSRGBSwapChainSupported() const noexcept override; + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + + bool canCreateFence() noexcept override; + Fence* createFence() noexcept override; + void destroyFence(Fence* fence) noexcept override; + FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override; + + OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImage(ExternalTexture* texture) noexcept override; + bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + + /** + * Logs glGetError() to slog.e + * @param name a string giving some context on the error. Typically __func__. + */ + static void logEglError(const char* name) noexcept; + static void logEglError(const char* name, EGLint error) noexcept; + static const char* getEglErrorName(EGLint error) noexcept; + + /** + * Calls glGetError() to clear the current error flags. logs a warning to log.w if + * an error was pending. + */ + static void clearGlError() noexcept; + + /** + * Always use this instead of eglMakeCurrent(). + */ + EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept; + + // TODO: this should probably use getters instead. + EGLDisplay mEGLDisplay = EGL_NO_DISPLAY; + EGLContext mEGLContext = EGL_NO_CONTEXT; + EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE; + EGLSurface mCurrentReadSurface = EGL_NO_SURFACE; + EGLSurface mEGLDummySurface = EGL_NO_SURFACE; + // mEGLConfig is valid only if ext.egl.KHR_no_config_context is false + EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR; + Config mContextAttribs; + std::vector mAdditionalContexts; + + // supported extensions detected at runtime + struct { + struct { + bool OES_EGL_image_external_essl3 = false; + } gl; + struct { + bool ANDROID_recordable = false; + bool KHR_create_context = false; + bool KHR_gl_colorspace = false; + bool KHR_no_config_context = false; + bool KHR_surfaceless_context = false; + } egl; + } ext; + + void initializeGlExtensions() noexcept; + +protected: + EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformEGLAndroid.h b/package/ios/libs/filament/include/backend/platforms/PlatformEGLAndroid.h new file mode 100644 index 00000000..32f83038 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformEGLAndroid.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H + +#include +#include +#include +#include + +#include +#include + +namespace filament::backend { + +class ExternalStreamManagerAndroid; + +/** + * A concrete implementation of OpenGLPlatform and subclass of PlatformEGL that supports + * EGL on Android. It adds Android streaming functionality to PlatformEGL. + */ +class PlatformEGLAndroid : public PlatformEGL { +public: + + PlatformEGLAndroid() noexcept; + ~PlatformEGLAndroid() noexcept override; + +protected: + + // -------------------------------------------------------------------------------------------- + // Platform Interface + + /** + * Returns the Android SDK version. + * @return Android SDK version. + */ + int getOSVersion() const noexcept override; + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + /** + * Set the presentation time using `eglPresentationTimeANDROID` + * @param presentationTimeInNanosecond + */ + void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept override; + + + Stream* createStream(void* nativeStream) noexcept override; + void destroyStream(Stream* stream) noexcept override; + void attach(Stream* stream, intptr_t tname) noexcept override; + void detach(Stream* stream) noexcept override; + void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override; + + /** + * Converts a AHardwareBuffer to EGLImage + * @param source source.image is a AHardwareBuffer + * @return source.image contains an EGLImage + */ + AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override; + +private: + int mOSVersion; + ExternalStreamManagerAndroid& mExternalStreamManager; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_EGL_ANDROID_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformEGLHeadless.h b/package/ios/libs/filament/include/backend/platforms/PlatformEGLHeadless.h new file mode 100644 index 00000000..40d285b9 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformEGLHeadless.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H +#define TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H + +#include "PlatformEGL.h" + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports EGL with only headless swapchains. + */ +class PlatformEGLHeadless : public PlatformEGL { +public: + PlatformEGLHeadless() noexcept; + + Driver* createDriver(void* sharedContext, + const Platform::DriverConfig& driverConfig) noexcept override; + +protected: + bool isOpenGL() const noexcept override; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_DRIVER_OPENGL_PLATFORM_EGL_HEADLESS_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformGLX.h b/package/ios/libs/filament/include/backend/platforms/PlatformGLX.h new file mode 100644 index 00000000..b2be5e40 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformGLX.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H + +#include + +#include "bluegl/BlueGL.h" +#include + +#include + +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports GLX. + */ +class PlatformGLX : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final override { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + +private: + Display *mGLXDisplay; + GLXContext mGLXContext; + GLXFBConfig* mGLXConfig; + GLXPbuffer mDummySurface; + std::vector mPBuffers; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformWGL.h b/package/ios/libs/filament/include/backend/platforms/PlatformWGL.h new file mode 100644 index 00000000..6c16c305 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformWGL.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WGL_H + +#include + +#include +#include "utils/unwindows.h" + +#include +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports WGL. + */ +class PlatformWGL : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept final override { return 0; } + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + bool isExtraContextSupported() const noexcept override; + void createContext(bool shared) override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; + +protected: + HGLRC mContext = NULL; + HWND mHWnd = NULL; + HDC mWhdc = NULL; + PIXELFORMATDESCRIPTOR mPfd = {}; + std::vector mAdditionalContexts; + std::vector mAttribs; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_GLX_H diff --git a/package/ios/libs/filament/include/backend/platforms/PlatformWebGL.h b/package/ios/libs/filament/include/backend/platforms/PlatformWebGL.h new file mode 100644 index 00000000..92bff0c4 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/PlatformWebGL.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H + +#include + +#include + +#include + +namespace filament::backend { + +/** + * A concrete implementation of OpenGLPlatform that supports WebGL. + */ +class PlatformWebGL : public OpenGLPlatform { +protected: + // -------------------------------------------------------------------------------------------- + // Platform Interface + + Driver* createDriver(void* sharedGLContext, + const Platform::DriverConfig& driverConfig) noexcept override; + + int getOSVersion() const noexcept override; + + // -------------------------------------------------------------------------------------------- + // OpenGLPlatform Interface + + void terminate() noexcept override; + + SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; + SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; + void destroySwapChain(SwapChain* swapChain) noexcept override; + void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; + void commit(SwapChain* swapChain) noexcept override; +}; + +} // namespace filament::backend + +#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_WEBGL_H diff --git a/package/ios/libs/filament/include/backend/platforms/VulkanPlatform.h b/package/ios/libs/filament/include/backend/platforms/VulkanPlatform.h new file mode 100644 index 00000000..6201d644 --- /dev/null +++ b/package/ios/libs/filament/include/backend/platforms/VulkanPlatform.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H +#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace filament::backend { + +using SwapChain = Platform::SwapChain; + +/** + * Private implementation details for the provided vulkan platform. + */ +struct VulkanPlatformPrivate; + +/** + * A Platform interface that creates a Vulkan backend. + */ +class VulkanPlatform : public Platform, utils::PrivateImplementation { +public: + + /** + * A collection of handles to objects and metadata that comprises a Vulkan context. The client + * can instantiate this struct and pass to Engine::Builder::sharedContext if they wishes to + * share their vulkan context. This is specifically necessary if the client wishes to override + * the swapchain API. + */ + struct VulkanSharedContext { + VkInstance instance = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice logicalDevice = VK_NULL_HANDLE; + uint32_t graphicsQueueFamilyIndex = 0xFFFFFFFF; + // In the usual case, the client needs to allocate at least one more graphics queue + // for Filament, and this index is the param to pass into vkGetDeviceQueue. In the case + // where the gpu only has one graphics queue. Then the client needs to ensure that no + // concurrent access can occur. + uint32_t graphicsQueueIndex = 0xFFFFFFFF; + }; + + /** + * Shorthand for the pointer to the Platform SwapChain struct, we use it also as a handle (i.e. + * identifier for the swapchain). + */ + using SwapChainPtr = Platform::SwapChain*; + + /** + * Collection of images, formats, and extent (width/height) that defines the swapchain. + */ + struct SwapChainBundle { + utils::FixedCapacityVector colors; + VkImage depth = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkFormat depthFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent = {0, 0}; + }; + + VulkanPlatform(); + + ~VulkanPlatform() override; + + Driver* createDriver(void* sharedContext, + Platform::DriverConfig const& driverConfig) noexcept override; + + int getOSVersion() const noexcept override { + return 0; + } + + // ---------------------------------------------------- + // ---------- Platform Customization options ---------- + struct Customization { + /** + * The client can specify the GPU (i.e. VkDevice) for the platform. We allow the + * following preferences: + * 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`. Empty string + * by default. + * 2) Index of the device in the list as returned by + * `vkEnumeratePhysicalDevices`. -1 by default to indicate no preference. + */ + struct GPUPreference { + utils::CString deviceName; + int8_t index = -1; + } gpu; + + /** + * Whether the platform supports sRGB swapchain. Default is true. + */ + bool isSRGBSwapChainSupported = true; + + /** + * When the platform window is resized, we will flush and wait on the command queues + * before recreating the swapchain. Default is true. + */ + bool flushAndWaitOnWindowResize = true; + }; + + /** + * Client can override to indicate customized behavior or parameter for their platform. + * @return `Customization` struct that indicates the client's platform + * customizations. + */ + virtual Customization getCustomization() const noexcept { + return {}; + } + + // -------- End platform customization options -------- + // ---------------------------------------------------- + + /** + * Get the images handles and format of the memory backing the swapchain. This should be called + * after createSwapChain() or after recreateIfResized(). + * @param swapchain The handle returned by createSwapChain() + * @return An array of VkImages + */ + virtual SwapChainBundle getSwapChainBundle(SwapChainPtr handle); + + /** + * Acquire the next image for rendering. The `index` will be written with an non-negative + * integer that the backend can use to index into the `SwapChainBundle.colors` array. The + * corresponding VkImage will be used as the output color attachment. The client should signal + * the `clientSignal` semaphore when the image is ready to be used by the backend. + * @param handle The handle returned by createSwapChain() + * @param clientSignal The semaphore that the client will signal to indicate that the backend + * may render into the image. + * @param index Pointer to memory that will be filled with the index that corresponding + * to an image in the `SwapChainBundle.colors` array. + * @return Result of acquire + */ + virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index); + + /** + * Present the image corresponding to `index` to the display. The client should wait on + * `finishedDrawing` before presenting. + * @param handle The handle returned by createSwapChain() + * @param index Index that corresponding to an image in the + * `SwapChainBundle.colors` array. + * @param finishedDrawing Backend passes in a semaphore that the client will signal to + * indicate that the client may render into the image. + * @return Result of present + */ + virtual VkResult present(SwapChainPtr handle, uint32_t index, VkSemaphore finishedDrawing); + + /** + * Check if the surface size has changed. + * @param handle The handle returned by createSwapChain() + * @return Whether the swapchain has been resized + */ + virtual bool hasResized(SwapChainPtr handle); + + /** + * Carry out a recreation of the swapchain. + * @param handle The handle returned by createSwapChain() + * @return Result of the recreation + */ + virtual VkResult recreate(SwapChainPtr handle); + + /** + * Create a swapchain given a platform window, or if given a null `nativeWindow`, then we + * try to create a headless swapchain with the given `extent`. + * @param flags Optional parameters passed to the client as defined in + * Filament::SwapChain.h. + * @param extent Optional width and height that indicates the size of the headless swapchain. + * @return Result of the operation + */ + virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0, + VkExtent2D extent = {0, 0}); + + /** + * Destroy the swapchain. + * @param handle The handle returned by createSwapChain() + */ + virtual void destroy(SwapChainPtr handle); + + /** + * Clean up any resources owned by the Platform. For example, if the Vulkan instance handle was + * generated by the platform, we need to clean it up in this method. + */ + virtual void terminate(); + + /** + * @return The instance (VkInstance) for the Vulkan backend. + */ + VkInstance getInstance() const noexcept; + + /** + * @return The logical device (VkDevice) that was selected as the backend device. + */ + VkDevice getDevice() const noexcept; + + /** + * @return The physical device (i.e gpu) that was selected as the backend physical device. + */ + VkPhysicalDevice getPhysicalDevice() const noexcept; + + /** + * @return The family index of the graphics queue selected for the Vulkan backend. + */ + uint32_t getGraphicsQueueFamilyIndex() const noexcept; + + /** + * @return The index of the graphics queue (if there are multiple graphics queues) + * selected for the Vulkan backend. + */ + uint32_t getGraphicsQueueIndex() const noexcept; + + /** + * @return The queue that was selected for the Vulkan backend. + */ + VkQueue getGraphicsQueue() const noexcept; + +private: + // Platform dependent helper methods + using ExtensionSet = std::unordered_set; + static ExtensionSet getRequiredInstanceExtensions(); + + using SurfaceBundle = std::tuple; + static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, + uint64_t flags) noexcept; + + friend struct VulkanPlatformPrivate; +}; + +}// namespace filament::backend + +#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H diff --git a/package/ios/libs/filament/include/camutils/Bookmark.h b/package/ios/libs/filament/include/camutils/Bookmark.h new file mode 100644 index 00000000..44ec1d62 --- /dev/null +++ b/package/ios/libs/filament/include/camutils/Bookmark.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef CAMUTILS_BOOKMARK_H +#define CAMUTILS_BOOKMARK_H + +#include + +#include +#include + +namespace filament { +namespace camutils { + +template class FreeFlightManipulator; +template class OrbitManipulator; +template class MapManipulator; +template class Manipulator; + +enum class Mode { ORBIT, MAP, FREE_FLIGHT }; + +/** + * Opaque memento to a viewing position and orientation (e.g. the "home" camera position). + * + * This little struct is meant to be passed around by value and can be used to track camera + * animation between waypoints. In map mode this implements Van Wijk interpolation. + * + * @see Manipulator::getCurrentBookmark, Manipulator::jumpToBookmark + */ +template +struct CAMUTILS_PUBLIC Bookmark { + /** + * Interpolates between two bookmarks. The t argument must be between 0 and 1 (inclusive), and + * the two endpoints must have the same mode (ORBIT or MAP). + */ + static Bookmark interpolate(Bookmark a, Bookmark b, double t); + + /** + * Recommends a duration for animation between two MAP endpoints. The return value is a unitless + * multiplier. + */ + static double duration(Bookmark a, Bookmark b); + +private: + struct MapParams { + FLOAT extent; + filament::math::vec2 center; + }; + struct OrbitParams { + FLOAT phi; + FLOAT theta; + FLOAT distance; + filament::math::vec3 pivot; + }; + struct FlightParams { + FLOAT pitch; + FLOAT yaw; + filament::math::vec3 position; + }; + Mode mode; + MapParams map; + OrbitParams orbit; + FlightParams flight; + friend class FreeFlightManipulator; + friend class OrbitManipulator; + friend class MapManipulator; +}; + +} // namespace camutils +} // namespace filament + +#endif // CAMUTILS_BOOKMARK_H diff --git a/package/ios/libs/filament/include/camutils/Manipulator.h b/package/ios/libs/filament/include/camutils/Manipulator.h new file mode 100644 index 00000000..2cc8a4da --- /dev/null +++ b/package/ios/libs/filament/include/camutils/Manipulator.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef CAMUTILS_MANIPULATOR_H +#define CAMUTILS_MANIPULATOR_H + +#include +#include + +#include +#include +#include + +#include + +namespace filament { +namespace camutils { + +enum class Fov { VERTICAL, HORIZONTAL }; + +/** + * Helper that enables camera interaction similar to sketchfab or Google Maps. + * + * Clients notify the camera manipulator of various mouse or touch events, then periodically call + * its getLookAt() method so that they can adjust their camera(s). Three modes are supported: ORBIT, + * MAP, and FREE_FLIGHT. To construct a manipulator instance, the desired mode is passed into the + * create method. + * + * Usage example: + * + * using CameraManipulator = camutils::Manipulator; + * CameraManipulator* manip; + * + * void init() { + * manip = CameraManipulator::Builder() + * .viewport(1024, 768) + * .build(camutils::Mode::ORBIT); + * } + * + * void onMouseDown(int x, int y) { + * manip->grabBegin(x, y, false); + * } + * + * void onMouseMove(int x, int y) { + * manip->grabUpdate(x, y); + * } + * + * void onMouseUp(int x, int y) { + * manip->grabEnd(); + * } + * + * void gameLoop() { + * while (true) { + * filament::math::float3 eye, center, up; + * manip->getLookAt(&eye, ¢er, &up); + * camera->lookAt(eye, center, up); + * render(); + * } + * } + * + * @see Bookmark + */ +template +class CAMUTILS_PUBLIC Manipulator { +public: + using vec2 = filament::math::vec2; + using vec3 = filament::math::vec3; + using vec4 = filament::math::vec4; + + /** Opaque handle to a viewing position and orientation to facilitate camera animation. */ + using Bookmark = filament::camutils::Bookmark; + + /** Optional raycasting function to enable perspective-correct panning. */ + typedef bool (*RayCallback)(const vec3& origin, const vec3& dir, FLOAT* t, void* userdata); + + /** Builder state, direct access is allowed but Builder methods are preferred. **/ + struct Config { + int viewport[2]; + vec3 targetPosition; + vec3 upVector; + FLOAT zoomSpeed; + vec3 orbitHomePosition; + vec2 orbitSpeed; + Fov fovDirection; + FLOAT fovDegrees; + FLOAT farPlane; + vec2 mapExtent; + FLOAT mapMinDistance; + vec3 flightStartPosition; + FLOAT flightStartPitch; + FLOAT flightStartYaw; + FLOAT flightMaxSpeed; + FLOAT flightSpeedSteps; + vec2 flightPanSpeed; + FLOAT flightMoveDamping; + vec4 groundPlane; + RayCallback raycastCallback; + void* raycastUserdata; + }; + + struct Builder { + // Common properties + Builder& viewport(int width, int height); //! Width and height of the viewing area + Builder& targetPosition(FLOAT x, FLOAT y, FLOAT z); //! World-space position of interest, defaults to (0,0,0) + Builder& upVector(FLOAT x, FLOAT y, FLOAT z); //! Orientation for the home position, defaults to (0,1,0) + Builder& zoomSpeed(FLOAT val); //! Multiplied with scroll delta, defaults to 0.01 + + // Orbit mode properties + Builder& orbitHomePosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,1) + Builder& orbitSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01 + + // Map mode properties + Builder& fovDirection(Fov fov); //! The axis that's held constant when viewport changes + Builder& fovDegrees(FLOAT degrees); //! The full FOV (not the half-angle) + Builder& farPlane(FLOAT distance); //! The distance to the far plane + Builder& mapExtent(FLOAT worldWidth, FLOAT worldHeight); //! The ground size for computing home position + Builder& mapMinDistance(FLOAT mindist); //! Constrains the zoom-in level + + // Free flight properties + Builder& flightStartPosition(FLOAT x, FLOAT y, FLOAT z); //! Initial eye position in world space, defaults to (0,0,0) + Builder& flightStartOrientation(FLOAT pitch, FLOAT yaw); //! Initial orientation in pitch and yaw, defaults to (0,0) + Builder& flightMaxMoveSpeed(FLOAT maxSpeed); //! The maximum camera speed in world units per second, defaults to 10 + Builder& flightSpeedSteps(int steps); //! The number of speed steps adjustable with scroll wheel, defaults to 80 + Builder& flightPanSpeed(FLOAT x, FLOAT y); //! Multiplied with viewport delta, defaults to 0.01,0.01 + Builder& flightMoveDamping(FLOAT damping); //! Applies a deceleration to camera movement, defaults to 0 (no damping) + //! Lower values give slower damping times, a good default is 15 + //! Too high a value may lead to instability + + // Raycast properties + Builder& groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d); //! Plane equation used as a raycast fallback + Builder& raycastCallback(RayCallback cb, void* userdata); //! Raycast function for accurate grab-and-pan + + /** + * Creates a new camera manipulator, either ORBIT, MAP, or FREE_FLIGHT. + * + * Clients can simply use "delete" to destroy the manipulator. + */ + Manipulator* build(Mode mode); + + Config details = {}; + }; + + virtual ~Manipulator() = default; + + /** + * Gets the immutable mode of the manipulator. + */ + Mode getMode() const { return mMode; } + + /** + * Sets the viewport dimensions. The manipulator uses this to process grab events and raycasts. + */ + void setViewport(int width, int height); + + /** + * Gets the current orthonormal basis; this is usually called once per frame. + */ + void getLookAt(vec3* eyePosition, vec3* targetPosition, vec3* upward) const; + + /** + * Given a viewport coordinate, picks a point in the ground plane, or in the actual scene if the + * raycast callback was provided. + */ + bool raycast(int x, int y, vec3* result) const; + + /** + * Given a viewport coordinate, computes a picking ray (origin + direction). + */ + void getRay(int x, int y, vec3* origin, vec3* dir) const; + + /** + * Starts a grabbing session (i.e. the user is dragging around in the viewport). + * + * In MAP mode, this starts a panning session. + * In ORBIT mode, this starts either rotating or strafing. + * In FREE_FLIGHT mode, this starts a nodal panning session. + * + * @param x X-coordinate for point of interest in viewport space + * @param y Y-coordinate for point of interest in viewport space + * @param strafe ORBIT mode only; if true, starts a translation rather than a rotation + */ + virtual void grabBegin(int x, int y, bool strafe) = 0; + + /** + * Updates a grabbing session. + * + * This must be called at least once between grabBegin / grabEnd to dirty the camera. + */ + virtual void grabUpdate(int x, int y) = 0; + + /** + * Ends a grabbing session. + */ + virtual void grabEnd() = 0; + + /** + * Keys used to translate the camera in FREE_FLIGHT mode. + * FORWARD and BACKWARD dolly the camera forwards and backwards. + * LEFT and RIGHT strafe the camera left and right. + * UP and DOWN boom the camera upwards and downwards. + */ + enum class Key { + FORWARD, + LEFT, + BACKWARD, + RIGHT, + UP, + DOWN, + + COUNT + }; + + /** + * Signals that a key is now in the down state. + * + * In FREE_FLIGHT mode, the camera is translated forward and backward and strafed left and right + * depending on the depressed keys. This allows WASD-style movement. + */ + virtual void keyDown(Key key); + + /** + * Signals that a key is now in the up state. + * + * @see keyDown + */ + virtual void keyUp(Key key); + + /** + * In MAP and ORBIT modes, dollys the camera along the viewing direction. + * In FREE_FLIGHT mode, adjusts the move speed of the camera. + * + * @param x X-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode + * @param y Y-coordinate for point of interest in viewport space, ignored in FREE_FLIGHT mode + * @param scrolldelta In MAP and ORBIT modes, negative means "zoom in", positive means "zoom out" + * In FREE_FLIGHT mode, negative means "slower", positive means "faster" + */ + virtual void scroll(int x, int y, FLOAT scrolldelta) = 0; + + /** + * Processes input and updates internal state. + * + * This must be called once every frame before getLookAt is valid. + * + * @param deltaTime The amount of time, in seconds, passed since the previous call to update. + */ + virtual void update(FLOAT deltaTime); + + /** + * Gets a handle that can be used to reset the manipulator back to its current position. + * + * @see jumpToBookmark + */ + virtual Bookmark getCurrentBookmark() const = 0; + + /** + * Gets a handle that can be used to reset the manipulator back to its home position. + * + * @see jumpToBookmark + */ + virtual Bookmark getHomeBookmark() const = 0; + + /** + * Sets the manipulator position and orientation back to a stashed state. + * + * @see getCurrentBookmark, getHomeBookmark + */ + virtual void jumpToBookmark(const Bookmark& bookmark) = 0; + +protected: + Manipulator(Mode mode, const Config& props); + + virtual void setProperties(const Config& props); + + vec3 raycastFarPlane(int x, int y) const; + + const Mode mMode; + Config mProps; + vec3 mEye; + vec3 mTarget; +}; + +} // namespace camutils +} // namespace filament + +#endif /* CAMUTILS_MANIPULATOR_H */ diff --git a/package/ios/libs/filament/include/camutils/compiler.h b/package/ios/libs/filament/include/camutils/compiler.h new file mode 100644 index 00000000..5e5edf94 --- /dev/null +++ b/package/ios/libs/filament/include/camutils/compiler.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CAMUTILS_COMPILER_H +#define CAMUTILS_COMPILER_H + +#if __has_attribute(visibility) +# define CAMUTILS_PUBLIC __attribute__((visibility("default"))) +#else +# define CAMUTILS_PUBLIC +#endif + +#endif // CAMUTILS_COMPILER_H diff --git a/package/ios/libs/filament/include/filamat/Enums.h b/package/ios/libs/filament/include/filamat/Enums.h new file mode 100644 index 00000000..04b5ff8b --- /dev/null +++ b/package/ios/libs/filament/include/filamat/Enums.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_ENUMMANAGER_H +#define TNT_ENUMMANAGER_H + +#include +#include +#include + +#include + +namespace filamat { + +using Property = MaterialBuilder::Property; +using UniformType = MaterialBuilder::UniformType; +using SamplerType = MaterialBuilder::SamplerType; +using SubpassType = MaterialBuilder::SubpassType; +using SamplerFormat = MaterialBuilder::SamplerFormat; +using ParameterPrecision = MaterialBuilder::ParameterPrecision; +using OutputTarget = MaterialBuilder::OutputTarget; +using OutputQualifier = MaterialBuilder::VariableQualifier; +using OutputType = MaterialBuilder::OutputType; +using ConstantType = MaterialBuilder::ConstantType; + +// Convenience methods to convert std::string to Enum and also iterate over Enum values. +class Enums { +public: + + // Returns true if string "s" is a valid string representation of an element of enum T. + template + static bool isValid(const std::string& s) noexcept { + std::unordered_map& map = getMap(); + return map.find(s) != map.end(); + } + + // Return enum matching its string representation. Returns undefined if s is not a valid enum T + // value. You should always call isValid() first to validate a string before calling toEnum(). + template + static T toEnum(const std::string& s) noexcept { + std::unordered_map& map = getMap(); + return map.at(s); + } + + template + static std::string toString(T t) noexcept; + + // Return a map of all values in an enum with their string representation. + template + static std::unordered_map& map() noexcept { + std::unordered_map& map = getMap(); + return map; + }; + +private: + template + static std::unordered_map& getMap() noexcept; + + static std::unordered_map mStringToProperty; + static std::unordered_map mStringToUniformType; + static std::unordered_map mStringToSamplerType; + static std::unordered_map mStringToSubpassType; + static std::unordered_map mStringToSamplerFormat; + static std::unordered_map mStringToSamplerPrecision; + static std::unordered_map mStringToOutputTarget; + static std::unordered_map mStringToOutputQualifier; + static std::unordered_map mStringToOutputType; + static std::unordered_map mStringToConstantType; +}; + +template +std::string Enums::toString(T t) noexcept { + std::unordered_map& map = getMap(); + auto result = std::find_if(map.begin(), map.end(), [t](auto& pair) { + return pair.second == t; + }); + if (result != map.end()) { + return result->first; + } + return ""; +} + +} // namespace filamat + +#endif //TNT_ENUMMANAGER_H diff --git a/package/ios/libs/filament/include/filamat/IncludeCallback.h b/package/ios/libs/filament/include/filamat/IncludeCallback.h new file mode 100644 index 00000000..659ba289 --- /dev/null +++ b/package/ios/libs/filament/include/filamat/IncludeCallback.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_FILAMAT_INCLUDER_H +#define TNT_FILAMAT_INCLUDER_H + +#include + +#include + +namespace filamat { + +struct IncludeResult { + // The include name of the root file, as if it were being included. + // I.e., 'foobar.h' in the case of #include "foobar.h" + const utils::CString includeName; + + // The following fields should be filled out by the IncludeCallback when processing an include, + // or when calling resolveIncludes for the root file. + + // The full contents of the include file. This may contain additional, recursive include + // directives. + utils::CString text; + + // The line number for the first line of text (first line is 0). + size_t lineNumberOffset = 0; + + // The name of the include file. This gets passed as "includerName" for any includes inside of + // source. This field isn't used by the include system; it's up to the callback to give meaning + // to this value and interpret it accordingly. In the case of DirIncluder, this is an empty + // string to represent the root include file, and a canonical path for subsequent included + // files. + utils::CString name; +}; + +/** + * A callback invoked by the include system when an #include "file.h" directive is found. + * + * For example, if a file main.h includes file.h on line 10, then IncludeCallback would be called + * with the following: + * includeCallback("main.h", {.includeName = "file.h" }) + * It's then up to the IncludeCallback to fill out the .text, .name, and (optionally) + * lineNumberOffset fields. + * + * @param includedBy is the value that was given to IncludeResult.name for this source file, or + * the empty string for the root source file. + * @param result is the IncludeResult that the callback should fill out. + * @return true, if the include was resolved successfully, false otherwise. + * + * For an example of implementing this callback, see tools/matc/src/matc/DirIncluder.h. + */ +using IncludeCallback = std::function; + +} // namespace filamat + +#endif diff --git a/package/ios/libs/filament/include/filamat/MaterialBuilder.h b/package/ios/libs/filament/include/filamat/MaterialBuilder.h new file mode 100644 index 00000000..bd586fe9 --- /dev/null +++ b/package/ios/libs/filament/include/filamat/MaterialBuilder.h @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2017 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. + */ + +//! \file + +#ifndef TNT_FILAMAT_MATERIAL_PACKAGE_BUILDER_H +#define TNT_FILAMAT_MATERIAL_PACKAGE_BUILDER_H + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace utils { +class JobSystem; +} + +namespace filament { +class BufferInterfaceBlock; +} + +namespace filamat { + +struct MaterialInfo; +struct Variant; +class ChunkContainer; + +class UTILS_PUBLIC MaterialBuilderBase { +public: + /** + * High-level hint that works in concert with TargetApi to determine the shader models (used to + * generate GLSL) and final output representations (spirv and/or text). + * When generating the GLSL this is used to differentiate OpenGL from OpenGLES, it is also + * used to make some performance adjustments. + */ + enum class Platform { + DESKTOP, + MOBILE, + ALL + }; + + /** + * TargetApi defines which language after transpilation will be used, it is used to + * account for some differences between these languages when generating the GLSL. + */ + enum class TargetApi : uint8_t { + OPENGL = 0x01u, + VULKAN = 0x02u, + METAL = 0x04u, + ALL = OPENGL | VULKAN | METAL + }; + + /* + * Generally we generate GLSL that will be converted to SPIRV, optimized and then + * transpiled to the backend's language such as MSL, ESSL300, GLSL410 or SPIRV, in this + * case the generated GLSL uses ESSL310 or GLSL450 and has Vulkan semantics and + * TargetLanguage::SPIRV must be used. + * + * However, in some cases (e.g. when no optimization is asked) we generate the *final* GLSL + * directly, this GLSL must be ESSL300 or GLSL410 and cannot use any Vulkan syntax, for this + * situation we use TargetLanguage::GLSL. In this case TargetApi is guaranteed to be OPENGL. + * + * Note that TargetLanguage::GLSL is not the common case, as it is generally not used in + * release builds. + * + * Also note that glslang performs semantics analysis on whichever GLSL ends up being generated. + */ + enum class TargetLanguage { + GLSL, // GLSL with OpenGL 4.1 / OpenGL ES 3.0 semantics + SPIRV // GLSL with Vulkan semantics + }; + + enum class Optimization { + NONE, + PREPROCESSOR, + SIZE, + PERFORMANCE + }; + + /** + * Initialize MaterialBuilder. + * + * init must be called first before building any materials. + */ + static void init(); + + /** + * Release internal MaterialBuilder resources. + * + * Call shutdown when finished building materials to release all internal resources. After + * calling shutdown, another call to MaterialBuilder::init must precede another material build. + */ + static void shutdown(); + +protected: + // Looks at platform and target API, then decides on shader models and output formats. + void prepare(bool vulkanSemantics, filament::backend::FeatureLevel featureLevel); + + using ShaderModel = filament::backend::ShaderModel; + Platform mPlatform = Platform::DESKTOP; + TargetApi mTargetApi = (TargetApi) 0; + Optimization mOptimization = Optimization::PERFORMANCE; + bool mPrintShaders = false; + bool mGenerateDebugInfo = false; + bool mIncludeEssl1 = true; + utils::bitset32 mShaderModels; + struct CodeGenParams { + ShaderModel shaderModel; + TargetApi targetApi; + TargetLanguage targetLanguage; + filament::backend::FeatureLevel featureLevel; + }; + std::vector mCodeGenPermutations; + + // Keeps track of how many times MaterialBuilder::init() has been called without a call to + // MaterialBuilder::shutdown(). Internally, glslang does something similar. We keep track for + // ourselves, so we can inform the user if MaterialBuilder::init() hasn't been called before + // attempting to build a material. + static std::atomic materialBuilderClients; +}; + +// Utility function that looks at an Engine backend to determine TargetApi +inline constexpr MaterialBuilderBase::TargetApi targetApiFromBackend( + filament::backend::Backend backend) noexcept { + using filament::backend::Backend; + using TargetApi = MaterialBuilderBase::TargetApi; + switch (backend) { + case Backend::DEFAULT: return TargetApi::ALL; + case Backend::OPENGL: return TargetApi::OPENGL; + case Backend::VULKAN: return TargetApi::VULKAN; + case Backend::METAL: return TargetApi::METAL; + case Backend::NOOP: return TargetApi::OPENGL; + } +} + +/** + * MaterialBuilder builds Filament materials from shader code. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filamat; + * + * // Must be called before any materials can be built. + * MaterialBuilder::init(); + + * MaterialBuilder builder; + * builder + * .name("My material") + * .material("void material (inout MaterialInputs material) {" + * " prepareMaterial(material);" + * " material.baseColor.rgb = float3(1.0, 0.0, 0.0);" + * "}") + * .shading(MaterialBuilder::Shading::LIT) + * .targetApi(MaterialBuilder::TargetApi::ALL) + * .platform(MaterialBuilder::Platform::ALL); + + * Package package = builder.build(); + * if (package.isValid()) { + * // success! + * } + + * // Call when finished building all materials to release internal + * // MaterialBuilder resources. + * MaterialBuilder::shutdown(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see filament::Material + */ +class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { +public: + MaterialBuilder(); + ~MaterialBuilder(); + + MaterialBuilder(const MaterialBuilder& rhs) = delete; + MaterialBuilder& operator=(const MaterialBuilder& rhs) = delete; + + MaterialBuilder(MaterialBuilder&& rhs) noexcept = default; + MaterialBuilder& operator=(MaterialBuilder&& rhs) noexcept = default; + + static constexpr size_t MATERIAL_VARIABLES_COUNT = 4; + enum class Variable : uint8_t { + CUSTOM0, + CUSTOM1, + CUSTOM2, + CUSTOM3 + // when adding more variables, make sure to update MATERIAL_VARIABLES_COUNT + }; + + using MaterialDomain = filament::MaterialDomain; + using RefractionMode = filament::RefractionMode; + using RefractionType = filament::RefractionType; + using ReflectionMode = filament::ReflectionMode; + using VertexAttribute = filament::VertexAttribute; + + using ShaderQuality = filament::ShaderQuality; + using BlendingMode = filament::BlendingMode; + using Shading = filament::Shading; + using Interpolation = filament::Interpolation; + using VertexDomain = filament::VertexDomain; + using TransparencyMode = filament::TransparencyMode; + using SpecularAmbientOcclusion = filament::SpecularAmbientOcclusion; + + using AttributeType = filament::backend::UniformType; + using UniformType = filament::backend::UniformType; + using ConstantType = filament::backend::ConstantType; + using SamplerType = filament::backend::SamplerType; + using SubpassType = filament::backend::SubpassType; + using SamplerFormat = filament::backend::SamplerFormat; + using ParameterPrecision = filament::backend::Precision; + using Precision = filament::backend::Precision; + using CullingMode = filament::backend::CullingMode; + using FeatureLevel = filament::backend::FeatureLevel; + + enum class VariableQualifier : uint8_t { + OUT + }; + + enum class OutputTarget : uint8_t { + COLOR, + DEPTH + }; + + enum class OutputType : uint8_t { + FLOAT, + FLOAT2, + FLOAT3, + FLOAT4 + }; + + struct PreprocessorDefine { + std::string name; + std::string value; + + PreprocessorDefine(std::string name, std::string value) : + name(std::move(name)), value(std::move(value)) {} + }; + using PreprocessorDefineList = std::vector; + + + MaterialBuilder& noSamplerValidation(bool enabled) noexcept; + + //! Enable generation of ESSL 1.0 code in FL0 materials. + MaterialBuilder& includeEssl1(bool enabled) noexcept; + + //! Set the name of this material. + MaterialBuilder& name(const char* name) noexcept; + + //! Set the file name of this material file. Used in error reporting. + MaterialBuilder& fileName(const char* name) noexcept; + + //! Set the shading model. + MaterialBuilder& shading(Shading shading) noexcept; + + //! Set the interpolation mode. + MaterialBuilder& interpolation(Interpolation interpolation) noexcept; + + //! Add a parameter (i.e., a uniform) to this material. + MaterialBuilder& parameter(const char* name, UniformType type, + ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept; + + //! Add a parameter array to this material. + MaterialBuilder& parameter(const char* name, size_t size, UniformType type, + ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept; + + //! Add a constant parameter to this material. + template + using is_supported_constant_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + template> + MaterialBuilder& constant(const char *name, ConstantType type, T defaultValue = 0); + + /** + * Add a sampler parameter to this material. + * + * When SamplerType::SAMPLER_EXTERNAL is specified, format and precision are ignored. + */ + MaterialBuilder& parameter(const char* name, SamplerType samplerType, + SamplerFormat format = SamplerFormat::FLOAT, + ParameterPrecision precision = ParameterPrecision::DEFAULT, + bool multisample = false) noexcept; + + MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept; + + //! Custom variables (all float4). + MaterialBuilder& variable(Variable v, const char* name) noexcept; + + /** + * Require a specified attribute. + * + * position is always required and normal depends on the shading model. + */ + MaterialBuilder& require(VertexAttribute attribute) noexcept; + + //! Specify the domain that this material will operate in. + MaterialBuilder& materialDomain(MaterialBuilder::MaterialDomain materialDomain) noexcept; + + /** + * Set the code content of this material. + * + * Surface Domain + * -------------- + * + * Materials in the SURFACE domain must declare a function: + * ~~~~~ + * void material(inout MaterialInputs material) { + * prepareMaterial(material); + * material.baseColor.rgb = float3(1.0, 0.0, 0.0); + * } + * ~~~~~ + * this function *must* call `prepareMaterial(material)` before it returns. + * + * Post-process Domain + * ------------------- + * + * Materials in the POST_PROCESS domain must declare a function: + * ~~~~~ + * void postProcess(inout PostProcessInputs postProcess) { + * postProcess.color = float4(1.0); + * } + * ~~~~~ + * + * @param code The source code of the material. + * @param line The line number offset of the material, where 0 is the first line. Used for error + * reporting + */ + MaterialBuilder& material(const char* code, size_t line = 0) noexcept; + + /** + * Set the callback used for resolving include directives. + * The default is no callback, which disallows all includes. + */ + MaterialBuilder& includeCallback(IncludeCallback callback) noexcept; + + /** + * Set the vertex code content of this material. + * + * Surface Domain + * -------------- + * + * Materials in the SURFACE domain must declare a function: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void materialVertex(inout MaterialVertexInputs material) { + * + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Post-process Domain + * ------------------- + * + * Materials in the POST_PROCESS domain must declare a function: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * void postProcessVertex(inout PostProcessVertexInputs postProcess) { + * + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + * @param code The source code of the material. + * @param line The line number offset of the material, where 0 is the first line. Used for error + * reporting + */ + MaterialBuilder& materialVertex(const char* code, size_t line = 0) noexcept; + + + MaterialBuilder& quality(ShaderQuality quality) noexcept; + + MaterialBuilder& featureLevel(FeatureLevel featureLevel) noexcept; + + /** + * Set the blending mode for this material. When set to MASKED, alpha to coverage is turned on. + * You can override this behavior using alphaToCoverage(false). + */ + MaterialBuilder& blending(BlendingMode blending) noexcept; + + /** + * Set the blending mode of the post-lighting color for this material. + * Only OPAQUE, TRANSPARENT and ADD are supported, the default is TRANSPARENT. + * This setting requires the material property "postLightingColor" to be set. + */ + MaterialBuilder& postLightingBlending(BlendingMode blending) noexcept; + + //! Set the vertex domain for this material. + MaterialBuilder& vertexDomain(VertexDomain domain) noexcept; + + /** + * How triangles are culled by default (doesn't affect points or lines, BACK by default). + * Material instances can override this. + */ + MaterialBuilder& culling(CullingMode culling) noexcept; + + //! Enable / disable color-buffer write (enabled by default, material instances can override). + MaterialBuilder& colorWrite(bool enable) noexcept; + + //! Enable / disable depth-buffer write (enabled by default for opaque, disabled for others, material instances can override). + MaterialBuilder& depthWrite(bool enable) noexcept; + + //! Enable / disable depth based culling (enabled by default, material instances can override). + MaterialBuilder& depthCulling(bool enable) noexcept; + + //! Enable / disable instanced primitives (disabled by default). + MaterialBuilder& instanced(bool enable) noexcept; + + /** + * Double-sided materials don't cull faces, equivalent to culling(CullingMode::NONE). + * doubleSided() overrides culling() if called. + * When called with "false", this enables the capability for a run-time toggle. + */ + MaterialBuilder& doubleSided(bool doubleSided) noexcept; + + /** + * Any fragment with an alpha below this threshold is clipped (MASKED blending mode only). + * The mask threshold can also be controlled by using the float material parameter called + * `_maskThreshold`, or by calling + * @ref filament::MaterialInstance::setMaskThreshold "MaterialInstance::setMaskThreshold". + */ + MaterialBuilder& maskThreshold(float threshold) noexcept; + + /** + * Enables or disables alpha-to-coverage. When enabled, the coverage of a fragment is based + * on its alpha value. This parameter is only useful when MSAA is in use. Alpha to coverage + * is enabled automatically when the blend mode is set to MASKED; this behavior can be + * overridden by calling alphaToCoverage(false). + */ + MaterialBuilder& alphaToCoverage(bool enable) noexcept; + + //! The material output is multiplied by the shadowing factor (UNLIT model only). + MaterialBuilder& shadowMultiplier(bool shadowMultiplier) noexcept; + + //! This material casts transparent shadows. The blending mode must be TRANSPARENT or FADE. + MaterialBuilder& transparentShadow(bool transparentShadow) noexcept; + + /** + * Reduces specular aliasing for materials that have low roughness. Turning this feature on also + * helps preserve the shapes of specular highlights as an object moves away from the camera. + * When turned on, two float material parameters are added to control the effect: + * `_specularAAScreenSpaceVariance` and `_specularAAThreshold`. You can also use + * @ref filament::MaterialInstance::setSpecularAntiAliasingVariance + * "MaterialInstance::setSpecularAntiAliasingVariance" and + * @ref filament::MaterialInstance::setSpecularAntiAliasingThreshold + * "setSpecularAntiAliasingThreshold" + * + * Disabled by default. + */ + MaterialBuilder& specularAntiAliasing(bool specularAntiAliasing) noexcept; + + /** + * Sets the screen-space variance of the filter kernel used when applying specular + * anti-aliasing. The default value is set to 0.15. The specified value should be between 0 and + * 1 and will be clamped if necessary. + */ + MaterialBuilder& specularAntiAliasingVariance(float screenSpaceVariance) noexcept; + + /** + * Sets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. The default value is set to 0.2. The specified value should be between 0 and 1 + * and will be clamped if necessary. + */ + MaterialBuilder& specularAntiAliasingThreshold(float threshold) noexcept; + + /** + * Enables or disables the index of refraction (IoR) change caused by the clear coat layer when + * present. When the IoR changes, the base color is darkened. Disabling this feature preserves + * the base color as initially specified. + * + * Enabled by default. + */ + MaterialBuilder& clearCoatIorChange(bool clearCoatIorChange) noexcept; + + //! Enable / disable flipping of the Y coordinate of UV attributes, enabled by default. + MaterialBuilder& flipUV(bool flipUV) noexcept; + + //! Enable / disable multi-bounce ambient occlusion, disabled by default on mobile. + MaterialBuilder& multiBounceAmbientOcclusion(bool multiBounceAO) noexcept; + + //! Set the specular ambient occlusion technique. Disabled by default on mobile. + MaterialBuilder& specularAmbientOcclusion(SpecularAmbientOcclusion specularAO) noexcept; + + //! Specify the refraction + MaterialBuilder& refractionMode(RefractionMode refraction) noexcept; + + //! Specify the refraction type + MaterialBuilder& refractionType(RefractionType refractionType) noexcept; + + //! Specifies how reflections should be rendered (default is DEFAULT). + MaterialBuilder& reflectionMode(ReflectionMode mode) noexcept; + + //! Specifies how transparent objects should be rendered (default is DEFAULT). + MaterialBuilder& transparencyMode(TransparencyMode mode) noexcept; + + /** + * Enable / disable custom surface shading. Custom surface shading requires the LIT + * shading model. In addition, the following function must be defined in the fragment + * block: + * + * ~~~~~ + * vec3 surfaceShading(const MaterialInputs materialInputs, + * const ShadingData shadingData, const LightData lightData) { + * + * return vec3(1.0); // Compute surface shading with custom BRDF, etc. + * } + * ~~~~~ + * + * This function is invoked once per light. Please refer to the materials documentation + * for more information about the different parameters. + * + * @param customSurfaceShading Enables or disables custom surface shading + */ + MaterialBuilder& customSurfaceShading(bool customSurfaceShading) noexcept; + + /** + * Specifies desktop vs mobile; works in concert with TargetApi to determine the shader models + * (used to generate code) and final output representations (spirv and/or text). + */ + MaterialBuilder& platform(Platform platform) noexcept; + + /** + * Specifies OpenGL, Vulkan, or Metal. + * This can be called repeatedly to build for multiple APIs. + * Works in concert with Platform to determine the shader models (used to generate code) and + * final output representations (spirv and/or text). + * If linking against filamat_lite, only `OPENGL` is allowed. + */ + MaterialBuilder& targetApi(TargetApi targetApi) noexcept; + + /** + * Specifies the level of optimization to apply to the shaders (default is PERFORMANCE). + * If linking against filamat_lite, this _must_ be called with Optimization::NONE. + */ + MaterialBuilder& optimization(Optimization optimization) noexcept; + + // TODO: this is present here for matc's "--print" flag, but ideally does not belong inside + // MaterialBuilder. + //! If true, will output the generated GLSL shader code to stdout. + MaterialBuilder& printShaders(bool printShaders) noexcept; + + //! If true, will include debugging information in generated SPIRV. + MaterialBuilder& generateDebugInfo(bool generateDebugInfo) noexcept; + + //! Specifies a list of variants that should be filtered out during code generation. + MaterialBuilder& variantFilter(filament::UserVariantFilterMask variantFilter) noexcept; + + //! Adds a new preprocessor macro definition to the shader code. Can be called repeatedly. + MaterialBuilder& shaderDefine(const char* name, const char* value) noexcept; + + //! Add a new fragment shader output variable. Only valid for materials in the POST_PROCESS domain. + MaterialBuilder& output(VariableQualifier qualifier, OutputTarget target, Precision precision, + OutputType type, const char* name, int location = -1) noexcept; + + MaterialBuilder& enableFramebufferFetch() noexcept; + + MaterialBuilder& vertexDomainDeviceJittered(bool enabled) noexcept; + + /** + * Legacy morphing uses the data in the VertexAttribute slots (\c MORPH_POSITION_0, etc) and is + * limited to 4 morph targets. See filament::RenderableManager::Builder::morphing(). + */ + MaterialBuilder& useLegacyMorphing() noexcept; + + //! specify compute kernel group size + MaterialBuilder& groupSize(filament::math::uint3 groupSize) noexcept; + + /** + * Build the material. If you are using the Filament engine with this library, you should use + * the job system provided by Engine. + */ + Package build(utils::JobSystem& jobSystem) noexcept; + +public: + // The methods and types below are for internal use + /// @cond never + + /** + * Add a subpass parameter to this material. + */ + MaterialBuilder& subpass(SubpassType subpassType, + SamplerFormat format, ParameterPrecision precision, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, + SamplerFormat format, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, + ParameterPrecision precision, const char* name) noexcept; + MaterialBuilder& subpass(SubpassType subpassType, const char* name) noexcept; + + struct Parameter { + Parameter() noexcept: parameterType(INVALID) {} + + // Sampler + Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms) + : name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms) { } + + // Uniform + Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p) + : name(paramName), size(typeSize), uniformType(t), precision(p), parameterType(UNIFORM) { } + + // Subpass + Parameter(const char* paramName, SubpassType t, SamplerFormat f, ParameterPrecision p) + : name(paramName), size(1), precision(p), subpassType(t), format(f), parameterType(SUBPASS) { } + + utils::CString name; + size_t size; + UniformType uniformType; + ParameterPrecision precision; + SamplerType samplerType; + SubpassType subpassType; + SamplerFormat format; + bool multisample; + enum { + INVALID, + UNIFORM, + SAMPLER, + SUBPASS + } parameterType; + + bool isSampler() const { return parameterType == SAMPLER; } + bool isUniform() const { return parameterType == UNIFORM; } + bool isSubpass() const { return parameterType == SUBPASS; } + }; + + struct Output { + Output() noexcept = default; + Output(const char* outputName, VariableQualifier qualifier, OutputTarget target, + Precision precision, OutputType type, int location) noexcept + : name(outputName), qualifier(qualifier), target(target), precision(precision), + type(type), location(location) { } + + utils::CString name; + VariableQualifier qualifier; + OutputTarget target; + Precision precision; + OutputType type; + int location; + }; + + struct Constant { + utils::CString name; + ConstantType type; + union { + int32_t i; + float f; + bool b; + } defaultValue; + }; + + static constexpr size_t MATERIAL_PROPERTIES_COUNT = filament::MATERIAL_PROPERTIES_COUNT; + using Property = filament::Property; + + using PropertyList = bool[MATERIAL_PROPERTIES_COUNT]; + using VariableList = utils::CString[MATERIAL_VARIABLES_COUNT]; + using OutputList = std::vector; + + static constexpr size_t MAX_COLOR_OUTPUT = filament::backend::MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; + static constexpr size_t MAX_DEPTH_OUTPUT = 1; + static_assert(MAX_COLOR_OUTPUT == 8, + "When updating MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT, manually update post_process_inputs.fs" + " and post_process.fs"); + + // Preview the first shader generated by the given CodeGenParams. + // This is used to run Static Code Analysis before generating a package. + std::string peek(filament::backend::ShaderStage type, + const CodeGenParams& params, const PropertyList& properties) noexcept; + + // Returns true if any of the parameter samplers matches the specified type. + bool hasSamplerType(SamplerType samplerType) const noexcept; + + static constexpr size_t MAX_PARAMETERS_COUNT = 48; + static constexpr size_t MAX_SUBPASS_COUNT = 1; + static constexpr size_t MAX_BUFFERS_COUNT = 4; + using ParameterList = Parameter[MAX_PARAMETERS_COUNT]; + using SubpassList = Parameter[MAX_SUBPASS_COUNT]; + using BufferList = std::vector>; + using ConstantList = std::vector; + + // returns the number of parameters declared in this material + uint8_t getParameterCount() const noexcept { return mParameterCount; } + + // returns a list of at least getParameterCount() parameters + const ParameterList& getParameters() const noexcept { return mParameters; } + + // returns the number of parameters declared in this material + uint8_t getSubpassCount() const noexcept { return mSubpassCount; } + + // returns a list of at least getParameterCount() parameters + const SubpassList& getSubPasses() const noexcept { return mSubpasses; } + + filament::UserVariantFilterMask getVariantFilter() const { return mVariantFilter; } + + FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; } + /// @endcond + + struct Attribute { + std::string_view name; + AttributeType type; + MaterialBuilder::VertexAttribute location; + std::string getAttributeName() const noexcept { + return "mesh_" + std::string{ name }; + } + std::string getDefineName() const noexcept { + std::string uppercase{ name }; + transform(uppercase.cbegin(), uppercase.cend(), uppercase.begin(), ::toupper); + return "HAS_ATTRIBUTE_" + uppercase; + } + }; + + using AttributeDatabase = std::array; + + static inline AttributeDatabase const& getAttributeDatabase() noexcept { + return sAttributeDatabase; + } + +private: + static const AttributeDatabase sAttributeDatabase; + + void prepareToBuild(MaterialInfo& info) noexcept; + + // Return true if the shader is syntactically and semantically valid. + // This method finds all the properties defined in the fragment and + // vertex shaders of the material. + bool findAllProperties(CodeGenParams const& semanticCodeGenParams) noexcept; + + // Multiple calls to findProperties accumulate the property sets across fragment + // and vertex shaders in mProperties. + bool findProperties(filament::backend::ShaderStage type, + MaterialBuilder::PropertyList& allProperties, + CodeGenParams const& semanticCodeGenParams) noexcept; + + bool runSemanticAnalysis(MaterialInfo* inOutInfo, + CodeGenParams const& semanticCodeGenParams) noexcept; + + bool checkLiteRequirements() noexcept; + + bool checkMaterialLevelFeatures(MaterialInfo const& info) const noexcept; + + void writeCommonChunks(ChunkContainer& container, MaterialInfo& info) const noexcept; + void writeSurfaceChunks(ChunkContainer& container) const noexcept; + + bool generateShaders( + utils::JobSystem& jobSystem, + const std::vector& variants, ChunkContainer& container, + const MaterialInfo& info) const noexcept; + + bool hasCustomVaryings() const noexcept; + bool needsStandardDepthProgram() const noexcept; + + bool isLit() const noexcept { return mShading != filament::Shading::UNLIT; } + + utils::CString mMaterialName; + utils::CString mFileName; + + class ShaderCode { + public: + void setLineOffset(size_t offset) noexcept { mLineOffset = offset; } + void setUnresolved(const utils::CString& code) noexcept { + mIncludesResolved = false; + mCode = code; + } + + // Resolve all the #include directives, returns true if successful. + bool resolveIncludes(IncludeCallback callback, const utils::CString& fileName) noexcept; + + const utils::CString& getResolved() const noexcept { + assert(mIncludesResolved); + return mCode; + } + + size_t getLineOffset() const noexcept { return mLineOffset; } + + private: + utils::CString mCode; + size_t mLineOffset = 0; + bool mIncludesResolved = false; + }; + + ShaderCode mMaterialFragmentCode; + ShaderCode mMaterialVertexCode; + + IncludeCallback mIncludeCallback = nullptr; + + PropertyList mProperties; + ParameterList mParameters; + ConstantList mConstants; + SubpassList mSubpasses; + VariableList mVariables; + OutputList mOutputs; + BufferList mBuffers; + + ShaderQuality mShaderQuality = ShaderQuality::DEFAULT; + FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1; + BlendingMode mBlendingMode = BlendingMode::OPAQUE; + BlendingMode mPostLightingBlendingMode = BlendingMode::TRANSPARENT; + CullingMode mCullingMode = CullingMode::BACK; + Shading mShading = Shading::LIT; + MaterialDomain mMaterialDomain = MaterialDomain::SURFACE; + RefractionMode mRefractionMode = RefractionMode::NONE; + RefractionType mRefractionType = RefractionType::SOLID; + ReflectionMode mReflectionMode = ReflectionMode::DEFAULT; + Interpolation mInterpolation = Interpolation::SMOOTH; + VertexDomain mVertexDomain = VertexDomain::OBJECT; + TransparencyMode mTransparencyMode = TransparencyMode::DEFAULT; + + filament::AttributeBitset mRequiredAttributes; + + float mMaskThreshold = 0.4f; + float mSpecularAntiAliasingVariance = 0.15f; + float mSpecularAntiAliasingThreshold = 0.2f; + + filament::math::uint3 mGroupSize = { 1, 1, 1 }; + + bool mShadowMultiplier = false; + bool mTransparentShadow = false; + + uint8_t mParameterCount = 0; + uint8_t mSubpassCount = 0; + + bool mDoubleSided = false; + bool mDoubleSidedCapability = false; + bool mColorWrite = true; + bool mDepthTest = true; + bool mInstanced = false; + bool mDepthWrite = true; + bool mDepthWriteSet = false; + bool mAlphaToCoverage = false; + bool mAlphaToCoverageSet = false; + + bool mSpecularAntiAliasing = false; + bool mClearCoatIorChange = true; + + bool mFlipUV = true; + + bool mMultiBounceAO = false; + bool mMultiBounceAOSet = false; + + SpecularAmbientOcclusion mSpecularAO = SpecularAmbientOcclusion::NONE; + bool mSpecularAOSet = false; + + bool mCustomSurfaceShading = false; + + bool mEnableFramebufferFetch = false; + + bool mVertexDomainDeviceJittered = false; + + bool mUseLegacyMorphing = false; + + PreprocessorDefineList mDefines; + + filament::UserVariantFilterMask mVariantFilter = {}; + + bool mNoSamplerValidation = false; +}; + +} // namespace filamat + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif diff --git a/package/ios/libs/filament/include/filamat/Package.h b/package/ios/libs/filament/include/filamat/Package.h new file mode 100644 index 00000000..93e74a58 --- /dev/null +++ b/package/ios/libs/filament/include/filamat/Package.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMAT_PACKAGE_H +#define TNT_FILAMAT_PACKAGE_H + +#include +#include +#include + +#include +#include + +#include + +namespace filamat { + +class UTILS_PUBLIC Package { +public: + Package() = default; + + // Regular constructor + explicit Package(size_t size) : mSize(size) { + mPayload = new uint8_t[size]; + } + + Package(const void* src, size_t size) : Package(size) { + memcpy(mPayload, src, size); + } + + // Move Constructor + Package(Package&& other) noexcept : mPayload(other.mPayload), mSize(other.mSize), + mValid(other.mValid) { + other.mPayload = nullptr; + other.mSize = 0; + other.mValid = false; + } + + // Move assignment + Package& operator=(Package&& other) noexcept { + std::swap(mPayload, other.mPayload); + std::swap(mSize, other.mSize); + std::swap(mValid, other.mValid); + return *this; + } + + // Copy assignment operator disallowed. + Package& operator=(const Package& other) = delete; + + // Copy constructor disallowed. + Package(const Package& other) = delete; + + ~Package() { + delete[] mPayload; + } + + uint8_t* getData() const noexcept { + return mPayload; + } + + size_t getSize() const noexcept { + return mSize; + } + + uint8_t* getEnd() const noexcept { + return mPayload + mSize; + } + + void setValid(bool valid) noexcept { + mValid = valid; + } + + bool isValid() const noexcept { + return mValid; + } + + static Package invalidPackage() { + Package package(0); + package.setValid(false); + return package; + } + +private: + uint8_t* mPayload = nullptr; + size_t mSize = 0; + bool mValid = true; +}; + +} // namespace filamat +#endif diff --git a/package/ios/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h b/package/ios/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h new file mode 100644 index 00000000..815ff613 --- /dev/null +++ b/package/ios/libs/filament/include/filament-iblprefilter/IBLPrefilterContext.h @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_IBL_PREFILTER_IBLPREFILTER_H +#define TNT_IBL_PREFILTER_IBLPREFILTER_H + +#include +#include + +#include + +namespace filament { +class Engine; +class View; +class Scene; +class Renderer; +class Material; +class MaterialInstance; +class VertexBuffer; +class IndexBuffer; +class Camera; +class Texture; +} // namespace filament + +/** + * IBLPrefilterContext creates and initializes GPU state common to all environment map filters + * supported. Typically, only one instance per filament Engine of this object needs to exist. + * + * Usage Example: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * IBLPrefilterContext context(engine); + * IBLPrefilterContext::SpecularFilter filter(context); + * Texture* texture = filter(environment_cubemap); + * + * IndirectLight* indirectLight = IndirectLight::Builder() + * .reflections(texture) + * .build(engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC IBLPrefilterContext { +public: + + enum class Kernel : uint8_t { + D_GGX, // Trowbridge-reitz distribution + }; + + /** + * Creates an IBLPrefilter context. + * @param engine filament engine to use + */ + explicit IBLPrefilterContext(filament::Engine& engine); + + /** + * Destroys all GPU resources created during initialization. + */ + ~IBLPrefilterContext() noexcept; + + // not copyable + IBLPrefilterContext(IBLPrefilterContext const&) = delete; + IBLPrefilterContext& operator=(IBLPrefilterContext const&) = delete; + + // movable + IBLPrefilterContext(IBLPrefilterContext&& rhs) noexcept; + IBLPrefilterContext& operator=(IBLPrefilterContext&& rhs) noexcept; + + // ------------------------------------------------------------------------------------------- + + /** + * EquirectangularToCubemap is use to convert an equirectangluar image to a cubemap. + */ + class EquirectangularToCubemap { + public: + /** + * Creates a EquirectangularToCubemap processor. + * @param context IBLPrefilterContext to use + */ + explicit EquirectangularToCubemap(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~EquirectangularToCubemap() noexcept; + + EquirectangularToCubemap(EquirectangularToCubemap const&) = delete; + EquirectangularToCubemap& operator=(EquirectangularToCubemap const&) = delete; + EquirectangularToCubemap(EquirectangularToCubemap&& rhs) noexcept; + EquirectangularToCubemap& operator=(EquirectangularToCubemap&& rhs) noexcept; + + /** + * Converts an equirectangular image to a cubemap. + * @param equirectangular Texture to convert to a cubemap. + * - Can't be null. + * - Must be a 2d texture + * - Must have equirectangular geometry, that is width == 2*height. + * - Must be allocated with all mip levels. + * - Must be SAMPLEABLE + * @param outCubemap Output cubemap. If null the texture is automatically created + * with default parameters (size of 256 with 9 levels). + * - Must be a cubemap + * - Must have SAMPLEABLE and COLOR_ATTACHMENT usage bits + * @return returns outCubemap + */ + filament::Texture* operator()( + filament::Texture const* equirectangular, + filament::Texture* outCubemap = nullptr); + + private: + IBLPrefilterContext& mContext; + filament::Material* mEquirectMaterial = nullptr; + }; + + /** + * IrradianceFilter is a GPU based implementation of the diffuse probe pre-integration filter. + * An instance of IrradianceFilter is needed per filter configuration. A filter configuration + * contains the filter's kernel and sample count. + */ + class IrradianceFilter { + public: + using Kernel = Kernel; + + /** + * Filter configuration. + */ + struct Config { + uint16_t sampleCount = 1024u; //!< filter sample count (max 2048) + Kernel kernel = Kernel::D_GGX; //!< filter kernel + }; + + /** + * Filtering options for the current environment. + */ + struct Options { + float hdrLinear = 1024.0f; //!< no HDR compression up to this value + float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax + float lodOffset = 2.0f; //!< Good values are 2.0 or 3.0. Higher values help with heavily HDR inputs. + bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps + }; + + /** + * Creates a IrradianceFilter processor. + * @param context IBLPrefilterContext to use + * @param config Configuration of the filter + */ + IrradianceFilter(IBLPrefilterContext& context, Config config); + + /** + * Creates a filter with the default configuration. + * @param context IBLPrefilterContext to use + */ + explicit IrradianceFilter(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~IrradianceFilter() noexcept; + + IrradianceFilter(IrradianceFilter const&) = delete; + IrradianceFilter& operator=(IrradianceFilter const&) = delete; + IrradianceFilter(IrradianceFilter&& rhs) noexcept; + IrradianceFilter& operator=(IrradianceFilter&& rhs) noexcept; + + /** + * Generates an irradiance cubemap. Mipmaps are not generated even if present. + * @param options Options for this environment + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outIrradianceTexture Output irradiance texture or, if null, it is + * automatically created with some default parameters. + * outIrradianceTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages. + * + * @return returns outIrradianceTexture + */ + filament::Texture* operator()(Options options, + filament::Texture const* environmentCubemap, + filament::Texture* outIrradianceTexture = nullptr); + + /** + * Generates a prefiltered cubemap. + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outIrradianceTexture Output irradiance texture or, if null, it is + * automatically created with some default parameters. + * outIrradianceTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages. + * + * @return returns outReflectionsTexture + */ + filament::Texture* operator()( + filament::Texture const* environmentCubemap, + filament::Texture* outIrradianceTexture = nullptr); + + private: + filament::Texture* createIrradianceTexture(); + IBLPrefilterContext& mContext; + filament::Material* mKernelMaterial = nullptr; + filament::Texture* mKernelTexture = nullptr; + uint32_t mSampleCount = 0u; + }; + + /** + * SpecularFilter is a GPU based implementation of the specular probe pre-integration filter. + * An instance of SpecularFilter is needed per filter configuration. A filter configuration + * contains the filter's kernel and sample count. + */ + class SpecularFilter { + public: + using Kernel = Kernel; + + /** + * Filter configuration. + */ + struct Config { + uint16_t sampleCount = 1024u; //!< filter sample count (max 2048) + uint8_t levelCount = 5u; //!< number of roughness levels + Kernel kernel = Kernel::D_GGX; //!< filter kernel + }; + + /** + * Filtering options for the current environment. + */ + struct Options { + float hdrLinear = 1024.0f; //!< no HDR compression up to this value + float hdrMax = 16384.0f; //!< HDR compression between hdrLinear and hdrMax + float lodOffset = 1.0f; //!< Good values are 1.0 or 2.0. Higher values help with heavily HDR inputs. + bool generateMipmap = true; //!< set to false if the input environment map already has mipmaps + }; + + /** + * Creates a SpecularFilter processor. + * @param context IBLPrefilterContext to use + * @param config Configuration of the filter + */ + SpecularFilter(IBLPrefilterContext& context, Config config); + + /** + * Creates a filter with the default configuration. + * @param context IBLPrefilterContext to use + */ + explicit SpecularFilter(IBLPrefilterContext& context); + + /** + * Destroys all GPU resources created during initialization. + */ + ~SpecularFilter() noexcept; + + SpecularFilter(SpecularFilter const&) = delete; + SpecularFilter& operator=(SpecularFilter const&) = delete; + SpecularFilter(SpecularFilter&& rhs) noexcept; + SpecularFilter& operator=(SpecularFilter&& rhs) noexcept; + + /** + * Generates a prefiltered cubemap. + * @param options Options for this environment + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. If Options.generateMipmap is true, + * the mipmap levels will be overwritten, otherwise + * it is assumed that all levels are correctly initialized. + * @param outReflectionsTexture Output prefiltered texture or, if null, it is + * automatically created with some default parameters. + * outReflectionsTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages and at + * least the same number of levels than requested by Config. + * @return returns outReflectionsTexture + */ + filament::Texture* operator()(Options options, + filament::Texture const* environmentCubemap, + filament::Texture* outReflectionsTexture = nullptr); + + /** + * Generates a prefiltered cubemap. + * @param environmentCubemap Environment cubemap (input). Can't be null. + * This cubemap must be SAMPLEABLE and must have all its + * levels allocated. All mipmap levels will be overwritten. + * @param outReflectionsTexture Output prefiltered texture or, if null, it is + * automatically created with some default parameters. + * outReflectionsTexture must be a cubemap, it must have + * at least COLOR_ATTACHMENT and SAMPLEABLE usages and at + * least the same number of levels than requested by Config. + * @return returns outReflectionsTexture + */ + filament::Texture* operator()( + filament::Texture const* environmentCubemap, + filament::Texture* outReflectionsTexture = nullptr); + + // TODO: option for progressive filtering + + // TODO: add a callback for when the processing is done? + + private: + filament::Texture* createReflectionsTexture(); + IBLPrefilterContext& mContext; + filament::Material* mKernelMaterial = nullptr; + filament::Texture* mKernelTexture = nullptr; + uint32_t mSampleCount = 0u; + uint8_t mLevelCount = 1u; + }; + +private: + friend class Filter; + filament::Engine& mEngine; + filament::Renderer* mRenderer{}; + filament::Scene* mScene{}; + filament::VertexBuffer* mVertexBuffer{}; + filament::IndexBuffer* mIndexBuffer{}; + filament::Camera* mCamera{}; + utils::Entity mFullScreenQuadEntity{}; + utils::Entity mCameraEntity{}; + filament::View* mView{}; + filament::Material* mIntegrationMaterial{}; + filament::Material* mIrradianceIntegrationMaterial{}; +}; + +#endif //TNT_IBL_PREFILTER_IBLPREFILTER_H diff --git a/package/ios/libs/filament/include/filament/Box.h b/package/ios/libs/filament/include/filament/Box.h new file mode 100644 index 00000000..da6638da --- /dev/null +++ b/package/ios/libs/filament/include/filament/Box.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_BOX_H +#define TNT_FILAMENT_BOX_H + +#include + +#include +#include +#include +#include + +#include + +#include + +namespace filament { + +/** + * An axis aligned 3D box represented by its center and half-extent. + */ +class UTILS_PUBLIC Box { +public: + /** Center of the 3D box */ + math::float3 center = {}; + + /** Half extent from the center on all 3 axis */ + math::float3 halfExtent = {}; + + /** + * Whether the box is empty, i.e.: it's volume is null. + * @return true if the volume of the box is null + */ + constexpr bool isEmpty() const noexcept { + return length2(halfExtent) == 0; + } + + /** + * Computes the lowest coordinates corner of the box. + * @return center - halfExtent + */ + constexpr math::float3 getMin() const noexcept { + return center - halfExtent; + } + + /** + * Computes the largest coordinates corner of the box. + * @return center + halfExtent + */ + constexpr math::float3 getMax() const noexcept { + return center + halfExtent; + } + + /** + * Initializes the 3D box from its min / max coordinates on each axis + * @param min lowest coordinates corner of the box + * @param max largest coordinates corner of the box + * @return This bounding box + */ + Box& set(const math::float3& min, const math::float3& max) noexcept { + // float3 ctor needed for Visual Studio + center = (max + min) * math::float3(0.5f); + halfExtent = (max - min) * math::float3(0.5f); + return *this; + } + + /** + * Computes the bounding box of the union of two boxes + * @param box The box to be combined with + * @return The bounding box of the union of *this and box + */ + Box& unionSelf(const Box& box) noexcept { + set(min(getMin(), box.getMin()), max(getMax(), box.getMax())); + return *this; + } + + /** + * Translates the box *to* a given center position + * @param tr position to translate the box to + * @return A box centered in \p tr with the same extent than *this + */ + constexpr Box translateTo(const math::float3& tr) const noexcept { + return Box{ tr, halfExtent }; + } + + /** + * Computes the smallest bounding sphere of the box. + * @return The smallest sphere defined by its center (.xyz) and radius (.w) that contains *this + */ + math::float4 getBoundingSphere() const noexcept { + return { center, length(halfExtent) }; + } + + /** + * Transform a Box by a linear transform and a translation. + * + * @param m a 3x3 matrix, the linear transform + * @param t a float3, the translation + * @param box the box to transform + * @return the bounding box of the transformed box + */ + static Box transform(const math::mat3f& m, math::float3 const& t, const Box& box) noexcept { + return { m * box.center + t, abs(m) * box.halfExtent }; + } + + /** + * @deprecated Use transform() instead + * @see transform() + */ + friend Box rigidTransform(Box const& box, const math::mat4f& m) noexcept { + return transform(m.upperLeft(), m[3].xyz, box); + } +}; + +/** + * An axis aligned box represented by its min and max coordinates + */ +struct UTILS_PUBLIC Aabb { + + /** min coordinates */ + math::float3 min = FLT_MAX; + + /** max coordinates */ + math::float3 max = -FLT_MAX; + + /** + * Computes the center of the box. + * @return (max + min)/2 + */ + math::float3 center() const noexcept { + // float3 ctor needed for Visual Studio + return (max + min) * math::float3(0.5f); + } + + /** + * Computes the half-extent of the box. + * @return (max - min)/2 + */ + math::float3 extent() const noexcept { + // float3 ctor needed for Visual Studio + return (max - min) * math::float3(0.5f); + } + + /** + * Whether the box is empty, i.e.: it's volume is null or negative. + * @return true if min >= max, i.e: the volume of the box is null or negative + */ + bool isEmpty() const noexcept { + return any(greaterThanEqual(min, max)); + } + + struct Corners { + using value_type = math::float3; + value_type const* begin() const { return vertices; } + value_type const* end() const { return vertices + 8; } + value_type * begin() { return vertices; } + value_type * end() { return vertices + 8; } + value_type const* data() const { return vertices; } + value_type * data() { return vertices; } + size_t size() const { return 8; } + value_type const& operator[](size_t i) const noexcept { return vertices[i]; } + value_type& operator[](size_t i) noexcept { return vertices[i]; } + value_type vertices[8]; + }; + + /** + * Returns the 8 corner vertices of the AABB. + */ + Corners getCorners() const { + return Aabb::Corners{ .vertices = { + { min.x, min.y, min.z }, + { max.x, min.y, min.z }, + { min.x, max.y, min.z }, + { max.x, max.y, min.z }, + { min.x, min.y, max.z }, + { max.x, min.y, max.z }, + { min.x, max.y, max.z }, + { max.x, max.y, max.z }, + }}; + } + + /** + * Returns whether the box contains a given point. + * + * @param p the point to test + * @return the maximum signed distance to the box. Negative if p is in the box + */ + float contains(math::float3 p) const noexcept { + // we don't use std::max to avoid a dependency on + auto const maximum = [](auto a, auto b) { return a > b ? a : b; }; + float d = min.x - p.x; + d = maximum(d, min.y - p.y); + d = maximum(d, min.z - p.z); + d = maximum(d, p.x - max.x); + d = maximum(d, p.y - max.y); + d = maximum(d, p.z - max.z); + return d; + } + + /** + * Applies an affine transformation to the AABB. + * + * @param m the 3x3 transformation to apply + * @param t the translation + * @return the transformed box + */ + static Aabb transform(const math::mat3f& m, math::float3 const& t, const Aabb& box) noexcept { + // Fast AABB transformation per Jim Arvo in Graphics Gems (1990). + Aabb result{ t, t }; + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + const float a = m[col][row] * box.min[col]; + const float b = m[col][row] * box.max[col]; + result.min[row] += a < b ? a : b; + result.max[row] += a < b ? b : a; + } + } + return result; + } + + /** + * @deprecated Use transform() instead + * @see transform() + */ + Aabb transform(const math::mat4f& m) const noexcept { + return transform(m.upperLeft(), m[3].xyz, *this); + } +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BOX_H diff --git a/package/ios/libs/filament/include/filament/BufferObject.h b/package/ios/libs/filament/include/filament/BufferObject.h new file mode 100644 index 00000000..74a4b1ff --- /dev/null +++ b/package/ios/libs/filament/include/filament/BufferObject.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! \file + +#ifndef TNT_FILAMENT_BUFFEROBJECT_H +#define TNT_FILAMENT_BUFFEROBJECT_H + +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FBufferObject; + +class Engine; + +/** + * A generic GPU buffer containing data. + * + * Usage of this BufferObject is optional. For simple use cases it is not necessary. It is useful + * only when you need to share data between multiple VertexBuffer instances. It also allows you to + * efficiently swap-out the buffers in VertexBuffer. + * + * NOTE: For now this is only used for vertex data, but in the future we may use it for other things + * (e.g. compute). + * + * @see VertexBuffer + */ +class UTILS_PUBLIC BufferObject : public FilamentAPI { + struct BuilderDetails; + +public: + using BufferDescriptor = backend::BufferDescriptor; + using BindingType = backend::BufferObjectBinding; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the buffer in bytes. + * @param byteCount Maximum number of bytes the BufferObject can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& size(uint32_t byteCount) noexcept; + + /** + * The binding type for this buffer object. (defaults to VERTEX) + * @param BindingType Distinguishes between SSBO, VBO, etc. For now this must be VERTEX. + * @return A reference to this Builder for chaining calls. + */ + Builder& bindingType(BindingType bindingType) noexcept; + + /** + * Creates the BufferObject and returns a pointer to it. After creation, the buffer + * object is uninitialized. Use BufferObject::setBuffer() to initialize it. + * + * @param engine Reference to the filament::Engine to associate this BufferObject with. + * + * @return pointer to the newly created object + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see IndexBuffer::setBuffer + */ + BufferObject* UTILS_NONNULL build(Engine& engine); + private: + friend class FBufferObject; + }; + + /** + * Asynchronously copy-initializes a region of this BufferObject from the data provided. + * + * @param engine Reference to the filament::Engine associated with this BufferObject. + * @param buffer A BufferDescriptor representing the data used to initialize the BufferObject. + * @param byteOffset Offset in bytes into the BufferObject + */ + void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0); + + /** + * Returns the size of this BufferObject in elements. + * @return The maximum capacity of the BufferObject. + */ + size_t getByteCount() const noexcept; + +protected: + // prevent heap allocation + ~BufferObject() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_BUFFEROBJECT_H diff --git a/package/ios/libs/filament/include/filament/Camera.h b/package/ios/libs/filament/include/filament/Camera.h new file mode 100644 index 00000000..74f34af0 --- /dev/null +++ b/package/ios/libs/filament/include/filament/Camera.h @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_CAMERA_H +#define TNT_FILAMENT_CAMERA_H + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament { + +/** + * Camera represents the eye(s) through which the scene is viewed. + * + * A Camera has a position and orientation and controls the projection and exposure parameters. + * + * For stereoscopic rendering, a Camera maintains two separate "eyes": Eye 0 and Eye 1. These are + * arbitrary and don't necessarily need to correspond to "left" and "right". + * + * Creation and destruction + * ======================== + * + * In Filament, Camera is a component that must be associated with an entity. To do so, + * use Engine::createCamera(Entity). A Camera component is destroyed using + * Engine::destroyCameraComponent(Entity). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * utils::Entity myCameraEntity = utils::EntityManager::get().create(); + * filament::Camera* myCamera = engine->createCamera(myCameraEntity); + * myCamera->setProjection(45, 16.0/9.0, 0.1, 1.0); + * myCamera->lookAt({0, 1.60, 1}, {0, 0, 0}); + * engine->destroyCameraComponent(myCamera); + * ~~~~~~~~~~~ + * + * + * Coordinate system + * ================= + * + * The camera coordinate system defines the *view space*. The camera points towards its -z axis + * and is oriented such that its top side is in the direction of +y, and its right side in the + * direction of +x. + * + * @note + * Since the *near* and *far* planes are defined by the distance from the camera, + * their respective coordinates are -\p distance(near) and -\p distance(far). + * + * Clipping planes + * =============== + * + * The camera defines six *clipping planes* which together create a *clipping volume*. The + * geometry outside this volume is clipped. + * + * The clipping volume can either be a box or a frustum depending on which projection is used, + * respectively Projection.ORTHO or Projection.PERSPECTIVE. The six planes are specified either + * directly or indirectly using setProjection(). + * + * The six planes are: + * - left + * - right + * - bottom + * - top + * - near + * - far + * + * @note + * To increase the depth-buffer precision, the *far* clipping plane is always assumed to be at + * infinity for rendering. That is, it is not used to clip geometry during rendering. + * However, it is used during the culling phase (objects entirely behind the *far* + * plane are culled). + * + * + * Choosing the *near* plane distance + * ================================== + * + * The *near* plane distance greatly affects the depth-buffer resolution. + * + * Example: Precision at 1m, 10m, 100m and 1Km for various near distances assuming a 32-bit float + * depth-buffer: + * + * near (m) | 1 m | 10 m | 100 m | 1 Km + * -----------:|:------:|:-------:|:--------:|:--------: + * 0.001 | 7.2e-5 | 0.0043 | 0.4624 | 48.58 + * 0.01 | 6.9e-6 | 0.0001 | 0.0430 | 4.62 + * 0.1 | 3.6e-7 | 7.0e-5 | 0.0072 | 0.43 + * 1.0 | 0 | 3.8e-6 | 0.0007 | 0.07 + * + * As can be seen in the table above, the depth-buffer precision drops rapidly with the + * distance to the camera. + * + * Make sure to pick the highest *near* plane distance possible. + * + * On Vulkan and Metal platforms (or OpenGL platforms supporting either EXT_clip_control or + * ARB_clip_control extensions), the depth-buffer precision is much less dependent on the *near* + * plane value: + * + * near (m) | 1 m | 10 m | 100 m | 1 Km + * -----------:|:------:|:-------:|:--------:|:--------: + * 0.001 | 1.2e-7 | 9.5e-7 | 7.6e-6 | 6.1e-5 + * 0.01 | 1.2e-7 | 9.5e-7 | 7.6e-6 | 6.1e-5 + * 0.1 | 5.9e-8 | 9.5e-7 | 1.5e-5 | 1.2e-4 + * 1.0 | 0 | 9.5e-7 | 7.6e-6 | 1.8e-4 + * + * + * Choosing the *far* plane distance + * ================================= + * + * The far plane distance is always set internally to infinity for rendering, however it is used for + * culling and shadowing calculations. It is important to keep a reasonable ratio between + * the near and far plane distances. Typically a ratio in the range 1:100 to 1:100000 is + * commanded. Larger values may causes rendering artifacts or trigger assertions in debug builds. + * + * + * Exposure + * ======== + * + * The Camera is also used to set the scene's exposure, just like with a real camera. The lights + * intensity and the Camera exposure interact to produce the final scene's brightness. + * + * + * Stereoscopic rendering + * ====================== + * + * The Camera's transform (as set by setModelMatrix or via TransformManager) defines a "head" space, + * which typically corresponds to the location of the viewer's head. Each eye's transform is set + * relative to this head space by setEyeModelMatrix. + * + * Each eye also maintains its own projection matrix. These can be set with setCustomEyeProjection. + * Care must be taken to correctly set the projectionForCulling matrix, as well as its corresponding + * near and far values. The projectionForCulling matrix must define a frustum (in head space) that + * bounds the frustums of both eyes. Alternatively, culling may be disabled with + * View::setFrustumCullingEnabled. + * + * \see Frustum, View + */ +class UTILS_PUBLIC Camera : public FilamentAPI { +public: + //! Denotes the projection type used by this camera. \see setProjection + enum class Projection : int { + PERSPECTIVE, //!< perspective projection, objects get smaller as they are farther + ORTHO //!< orthonormal projection, preserves distances + }; + + //! Denotes a field-of-view direction. \see setProjection + enum class Fov : int { + VERTICAL, //!< the field-of-view angle is defined on the vertical axis + HORIZONTAL //!< the field-of-view angle is defined on the horizontal axis + }; + + /** Returns the projection matrix from the field-of-view. + * + * @param fovInDegrees full field-of-view in degrees. 0 < \p fov < 180. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + * @param direction direction of the \p fovInDegrees parameter. + * + * @see Fov. + */ + static math::mat4 projection(Fov direction, double fovInDegrees, + double aspect, double near, double far = INFINITY); + + /** Returns the projection matrix from the focal length. + * + * @param focalLengthInMillimeters lens's focal length in millimeters. \p focalLength > 0. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + static math::mat4 projection(double focalLengthInMillimeters, + double aspect, double near, double far = INFINITY); + + + /** Sets the projection matrix from a frustum defined by six planes. + * + * @param projection type of #Projection to use. + * + * @param left distance in world units from the camera to the left plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param right distance in world units from the camera to the right plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param bottom distance in world units from the camera to the bottom plane, + * at the near plane. + * Precondition: \p bottom != \p top. + * + * @param top distance in world units from the camera to the top plane, + * at the near plane. + * Precondition: \p left != \p right. + * + * @param near distance in world units from the camera to the near plane. The near plane's + * position in view space is z = -\p near. + * Precondition: \p near > 0 for PROJECTION::PERSPECTIVE or + * \p near != far for PROJECTION::ORTHO + * + * @param far distance in world units from the camera to the far plane. The far plane's + * position in view space is z = -\p far. + * Precondition: \p far > near for PROJECTION::PERSPECTIVE or + * \p far != near for PROJECTION::ORTHO + * + * @see Projection, Frustum + */ + void setProjection(Projection projection, + double left, double right, + double bottom, double top, + double near, double far); + + + /** Utility to set the projection matrix from the field-of-view. + * + * @param fovInDegrees full field-of-view in degrees. 0 < \p fov < 180. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + * @param direction direction of the \p fovInDegrees parameter. + * + * @see Fov. + */ + void setProjection(double fovInDegrees, double aspect, double near, double far, + Fov direction = Fov::VERTICAL); + + /** Utility to set the projection matrix from the focal length. + * + * @param focalLengthInMillimeters lens's focal length in millimeters. \p focalLength > 0. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setLensProjection(double focalLengthInMillimeters, + double aspect, double near, double far); + + + /** Sets a custom projection matrix. + * + * The projection matrix must define an NDC system that must match the OpenGL convention, + * that is all 3 axis are mapped to [-1, 1]. + * + * @param projection custom projection matrix used for rendering and culling + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setCustomProjection(math::mat4 const& projection, double near, double far) noexcept; + + /** Sets the projection matrix. + * + * The projection matrices must define an NDC system that must match the OpenGL convention, + * that is all 3 axis are mapped to [-1, 1]. + * + * @param projection custom projection matrix used for rendering + * @param projectionForCulling custom projection matrix used for culling + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + */ + void setCustomProjection(math::mat4 const& projection, math::mat4 const& projectionForCulling, + double near, double far) noexcept; + + /** Sets a custom projection matrix for each eye. + * + * The projectionForCulling, near, and far parameters establish a "culling frustum" which must + * encompass anything any eye can see. All projection matrices must be set simultaneously. The + * number of stereoscopic eyes is controlled by the stereoscopicEyeCount setting inside of + * Engine::Config. + * + * @param projection an array of projection matrices, only the first config.stereoscopicEyeCount + * are read + * @param count size of the projection matrix array to set, must be + * >= config.stereoscopicEyeCount + * @param projectionForCulling custom projection matrix for culling, must encompass both eyes + * @param near distance in world units from the camera to the culling near plane. \p near > 0. + * @param far distance in world units from the camera to the culling far plane. \p far > \p + * near. + * @see setCustomProjection + * @see Engine::Config::stereoscopicEyeCount + */ + void setCustomEyeProjection(math::mat4 const* UTILS_NONNULL projection, size_t count, + math::mat4 const& projectionForCulling, double near, double far); + + /** Sets an additional matrix that scales the projection matrix. + * + * This is useful to adjust the aspect ratio of the camera independent from its projection. + * First, pass an aspect of 1.0 to setProjection. Then set the scaling with the desired aspect + * ratio: + * + * const double aspect = width / height; + * + * // with Fov::HORIZONTAL passed to setProjection: + * camera->setScaling(double4 {1.0, aspect}); + * + * // with Fov::VERTICAL passed to setProjection: + * camera->setScaling(double4 {1.0 / aspect, 1.0}); + * + * + * By default, this is an identity matrix. + * + * @param scaling diagonal of the 2x2 scaling matrix to be applied after the projection matrix. + * + * @see setProjection, setLensProjection, setCustomProjection + */ + void setScaling(math::double2 scaling) noexcept; + + /** + * Sets an additional matrix that shifts the projection matrix. + * By default, this is an identity matrix. + * + * @param shift x and y translation added to the projection matrix, specified in NDC + * coordinates, that is, if the translation must be specified in pixels, + * shift must be scaled by 1.0 / { viewport.width, viewport.height }. + * + * @see setProjection, setLensProjection, setCustomProjection + */ + void setShift(math::double2 shift) noexcept; + + /** Returns the scaling amount used to scale the projection matrix. + * + * @return the diagonal of the scaling matrix applied after the projection matrix. + * + * @see setScaling + */ + math::double4 getScaling() const noexcept; + + /** Returns the shift amount used to translate the projection matrix. + * + * @return the 2D translation x and y offsets applied after the projection matrix. + * + * @see setShift + */ + math::double2 getShift() const noexcept; + + /** Returns the projection matrix used for rendering. + * + * The projection matrix used for rendering always has its far plane set to infinity. This + * is why it may differ from the matrix set through setProjection() or setLensProjection(). + * + * @param eyeId the index of the eye to return the projection matrix for, must be + * < config.stereoscopicEyeCount + * @return The projection matrix used for rendering + * + * @see setProjection, setLensProjection, setCustomProjection, getCullingProjectionMatrix, + * setCustomEyeProjection + */ + math::mat4 getProjectionMatrix(uint8_t eyeId = 0) const; + + + /** Returns the projection matrix used for culling (far plane is finite). + * + * @return The projection matrix set by setProjection or setLensProjection. + * + * @see setProjection, setLensProjection, getProjectionMatrix + */ + math::mat4 getCullingProjectionMatrix() const noexcept; + + + //! Returns the frustum's near plane + double getNear() const noexcept; + + //! Returns the frustum's far plane used for culling + double getCullingFar() const noexcept; + + /** Sets the camera's model matrix. + * + * Helper method to set the camera's entity transform component. + * It has the same effect as calling: + * + * ~~~~~~~~~~~{.cpp} + * engine.getTransformManager().setTransform( + * engine.getTransformManager().getInstance(camera->getEntity()), model); + * ~~~~~~~~~~~ + * + * @param model The camera position and orientation provided as a rigid transform matrix. + * + * @note The Camera "looks" towards its -z axis + * + * @warning \p model must be a rigid transform + */ + void setModelMatrix(const math::mat4& model) noexcept; + void setModelMatrix(const math::mat4f& model) noexcept; //!< @overload + + /** Set the position of an eye relative to this Camera (head). + * + * By default, both eyes' model matrices are identity matrices. + * + * For example, to position Eye 0 3cm leftwards and Eye 1 3cm rightwards: + * ~~~~~~~~~~~{.cpp} + * const mat4 leftEye = mat4::translation(double3{-0.03, 0.0, 0.0}); + * const mat4 rightEye = mat4::translation(double3{ 0.03, 0.0, 0.0}); + * camera.setEyeModelMatrix(0, leftEye); + * camera.setEyeModelMatrix(1, rightEye); + * ~~~~~~~~~~~ + * + * This method is not intended to be called every frame. Instead, to update the position of the + * head, use Camera::setModelMatrix. + * + * @param eyeId the index of the eye to set, must be < config.stereoscopicEyeCount + * @param model the model matrix for an individual eye + */ + void setEyeModelMatrix(uint8_t eyeId, math::mat4 const& model); + + /** Sets the camera's model matrix + * + * @param eye The position of the camera in world space. + * @param center The point in world space the camera is looking at. + * @param up A unit vector denoting the camera's "up" direction. + */ + void lookAt(math::double3 const& eye, + math::double3 const& center, + math::double3 const& up = math::double3{0, 1, 0}) noexcept; + + /** Returns the camera's model matrix + * + * Helper method to return the camera's entity transform component. + * It has the same effect as calling: + * + * ~~~~~~~~~~~{.cpp} + * engine.getTransformManager().getWorldTransform( + * engine.getTransformManager().getInstance(camera->getEntity())); + * ~~~~~~~~~~~ + * + * @return The camera's pose in world space as a rigid transform. Parent transforms, if any, + * are taken into account. + */ + math::mat4 getModelMatrix() const noexcept; + + //! Returns the camera's view matrix (inverse of the model matrix) + math::mat4 getViewMatrix() const noexcept; + + //! Returns the camera's position in world space + math::double3 getPosition() const noexcept; + + //! Returns the camera's normalized left vector + math::float3 getLeftVector() const noexcept; + + //! Returns the camera's normalized up vector + math::float3 getUpVector() const noexcept; + + //! Returns the camera's forward vector + math::float3 getForwardVector() const noexcept; + + //! Returns the camera's field of view in degrees + float getFieldOfViewInDegrees(Fov direction) const noexcept; + + //! Returns the camera's culling Frustum in world space + class Frustum getFrustum() const noexcept; + + //! Returns the entity representing this camera + utils::Entity getEntity() const noexcept; + + /** Sets this camera's exposure (default is f/16, 1/125s, 100 ISO) + * + * The exposure ultimately controls the scene's brightness, just like with a real camera. + * The default values provide adequate exposure for a camera placed outdoors on a sunny day + * with the sun at the zenith. + * + * @param aperture Aperture in f-stops, clamped between 0.5 and 64. + * A lower \p aperture value *increases* the exposure, leading to + * a brighter scene. Realistic values are between 0.95 and 32. + * + * @param shutterSpeed Shutter speed in seconds, clamped between 1/25,000 and 60. + * A lower shutter speed increases the exposure. Realistic values are + * between 1/8000 and 30. + * + * @param sensitivity Sensitivity in ISO, clamped between 10 and 204,800. + * A higher \p sensitivity increases the exposure. Realistic values are + * between 50 and 25600. + * + * @note + * With the default parameters, the scene must contain at least one Light of intensity + * similar to the sun (e.g.: a 100,000 lux directional light). + * + * @see LightManager, Exposure + */ + void setExposure(float aperture, float shutterSpeed, float sensitivity) noexcept; + + /** Sets this camera's exposure directly. Calling this method will set the aperture + * to 1.0, the shutter speed to 1.2 and the sensitivity will be computed to match + * the requested exposure (for a desired exposure of 1.0, the sensitivity will be + * set to 100 ISO). + * + * This method is useful when trying to match the lighting of other engines or tools. + * Many engines/tools use unit-less light intensities, which can be matched by setting + * the exposure manually. This can be typically achieved by setting the exposure to + * 1.0. + */ + void setExposure(float exposure) noexcept { + setExposure(1.0f, 1.2f, 100.0f * (1.0f / exposure)); + } + + //! returns this camera's aperture in f-stops + float getAperture() const noexcept; + + //! returns this camera's shutter speed in seconds + float getShutterSpeed() const noexcept; + + //! returns this camera's sensitivity in ISO + float getSensitivity() const noexcept; + + /** Returns the focal length in meters [m] for a 35mm camera. + * Eye 0's projection matrix is used to compute the focal length. + */ + double getFocalLength() const noexcept; + + /** + * Sets the camera focus distance. This is used by the Depth-of-field PostProcessing effect. + * @param distance Distance from the camera to the plane of focus in world units. + * Must be positive and larger than the near clipping plane. + */ + void setFocusDistance(float distance) noexcept; + + //! Returns the focus distance in world units + float getFocusDistance() const noexcept; + + /** + * Returns the inverse of a projection matrix. + * + * \param p the projection matrix to inverse + * \returns the inverse of the projection matrix \p p + */ + static math::mat4 inverseProjection(const math::mat4& p) noexcept; + + /** + * Returns the inverse of a projection matrix. + * @see inverseProjection(const math::mat4&) + */ + static math::mat4f inverseProjection(const math::mat4f& p) noexcept; + + /** + * Helper to compute the effective focal length taking into account the focus distance + * + * @param focalLength focal length in any unit (e.g. [m] or [mm]) + * @param focusDistance focus distance in same unit as focalLength + * @return the effective focal length in same unit as focalLength + */ + static double computeEffectiveFocalLength(double focalLength, double focusDistance) noexcept; + + /** + * Helper to compute the effective field-of-view taking into account the focus distance + * + * @param fovInDegrees full field of view in degrees + * @param focusDistance focus distance in meters [m] + * @return effective full field of view in degrees + */ + static double computeEffectiveFov(double fovInDegrees, double focusDistance) noexcept; + +protected: + // prevent heap allocation + ~Camera() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_CAMERA_H diff --git a/package/ios/libs/filament/include/filament/Color.h b/package/ios/libs/filament/include/filament/Color.h new file mode 100644 index 00000000..30b77856 --- /dev/null +++ b/package/ios/libs/filament/include/filament/Color.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_COLOR_H +#define TNT_FILAMENT_COLOR_H + +#include + +#include +#include + +#include +#include + +namespace filament { + +//! RGB color in linear space +using LinearColor = math::float3; + +//! RGB color in sRGB space +using sRGBColor = math::float3; + +//! RGBA color in linear space, with alpha +using LinearColorA = math::float4; + +//! RGBA color in sRGB space, with alpha +using sRGBColorA = math::float4; + +//! types of RGB colors +enum class RgbType : uint8_t { + sRGB, //!< the color is defined in Rec.709-sRGB-D65 (sRGB) space + LINEAR, //!< the color is defined in Rec.709-Linear-D65 ("linear sRGB") space +}; + +//! types of RGBA colors +enum class RgbaType : uint8_t { + /** + * the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values + * have not been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <1,0,0,0.5>) + */ + sRGB, + /** + * the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the + * RGB values have not been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <1,0,0,0.5>) + */ + LINEAR, + /** + * the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values + * have been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <0.5,0,0,0.5>) + */ + PREMULTIPLIED_sRGB, + /** + * the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the + * RGB values have been pre-multiplied by the alpha (for instance, a 50% + * transparent red is <0.5,0,0,0.5>) + */ + PREMULTIPLIED_LINEAR +}; + +//! type of color conversion to use when converting to/from sRGB and linear spaces +enum ColorConversion { + ACCURATE, //!< accurate conversion using the sRGB standard + FAST //!< fast conversion using a simple gamma 2.2 curve +}; + +/** + * Utilities to manipulate and convert colors + */ +class UTILS_PUBLIC Color { +public: + //! converts an RGB color to linear space, the conversion depends on the specified type + static LinearColor toLinear(RgbType type, math::float3 color); + + //! converts an RGBA color to linear space, the conversion depends on the specified type + static LinearColorA toLinear(RgbaType type, math::float4 color); + + //! converts an RGB color in sRGB space to an RGB color in linear space + template + static LinearColor toLinear(sRGBColor const& color); + + /** + * Converts an RGB color in Rec.709-Linear-D65 ("linear sRGB") space to an + * RGB color in Rec.709-sRGB-D65 (sRGB) space. + */ + template + static sRGBColor toSRGB(LinearColor const& color); + + /** + * Converts an RGBA color in Rec.709-sRGB-D65 (sRGB) space to an RGBA color in + * Rec.709-Linear-D65 ("linear sRGB") space the alpha component is left unmodified. + */ + template + static LinearColorA toLinear(sRGBColorA const& color); + + /** + * Converts an RGBA color in Rec.709-Linear-D65 ("linear sRGB") space to + * an RGBA color in Rec.709-sRGB-D65 (sRGB) space the alpha component is + * left unmodified. + */ + template + static sRGBColorA toSRGB(LinearColorA const& color); + + /** + * Converts a correlated color temperature to a linear RGB color in sRGB + * space the temperature must be expressed in kelvin and must be in the + * range 1,000K to 15,000K. + */ + static LinearColor cct(float K); + + /** + * Converts a CIE standard illuminant series D to a linear RGB color in + * sRGB space the temperature must be expressed in kelvin and must be in + * the range 4,000K to 25,000K + */ + static LinearColor illuminantD(float K); + + /** + * Computes the Beer-Lambert absorption coefficients from the specified + * transmittance color and distance. The computed absorption will guarantee + * the white light will become the specified color at the specified distance. + * The output of this function can be used as the absorption parameter of + * materials that use refraction. + * + * @param color the desired linear RGB color in sRGB space + * @param distance the distance at which white light should become the specified color + * + * @return absorption coefficients for the Beer-Lambert law + */ + static math::float3 absorptionAtDistance(LinearColor const& color, float distance); + +private: + static math::float3 sRGBToLinear(math::float3 color) noexcept; + static math::float3 linearToSRGB(math::float3 color) noexcept; +}; + +// Use the default implementation from the header +template<> +inline LinearColor Color::toLinear(sRGBColor const& color) { + return pow(color, 2.2f); +} + +template<> +inline LinearColorA Color::toLinear(sRGBColorA const& color) { + return LinearColorA{pow(color.rgb, 2.2f), color.a}; +} + +template<> +inline LinearColor Color::toLinear(sRGBColor const& color) { + return sRGBToLinear(color); +} + +template<> +inline LinearColorA Color::toLinear(sRGBColorA const& color) { + return LinearColorA{sRGBToLinear(color.rgb), color.a}; +} + +// Use the default implementation from the header +template<> +inline sRGBColor Color::toSRGB(LinearColor const& color) { + return pow(color, 1.0f / 2.2f); +} + +template<> +inline sRGBColorA Color::toSRGB(LinearColorA const& color) { + return sRGBColorA{pow(color.rgb, 1.0f / 2.2f), color.a}; +} + +template<> +inline sRGBColor Color::toSRGB(LinearColor const& color) { + return linearToSRGB(color); +} + +template<> +inline sRGBColorA Color::toSRGB(LinearColorA const& color) { + return sRGBColorA{linearToSRGB(color.rgb), color.a}; +} + +inline LinearColor Color::toLinear(RgbType type, math::float3 color) { + return (type == RgbType::LINEAR) ? color : Color::toLinear(color); +} + +// converts an RGBA color to linear space +// the conversion depends on the specified type +inline LinearColorA Color::toLinear(RgbaType type, math::float4 color) { + switch (type) { + case RgbaType::sRGB: + return Color::toLinear(color) * math::float4{color.a, color.a, color.a, 1.0f}; + case RgbaType::LINEAR: + return color * math::float4{color.a, color.a, color.a, 1.0f}; + case RgbaType::PREMULTIPLIED_sRGB: + return Color::toLinear(color); + case RgbaType::PREMULTIPLIED_LINEAR: + return color; + } +} + +} // namespace filament + +#endif // TNT_FILAMENT_COLOR_H diff --git a/package/ios/libs/filament/include/filament/ColorGrading.h b/package/ios/libs/filament/include/filament/ColorGrading.h new file mode 100644 index 00000000..e5c8f3ca --- /dev/null +++ b/package/ios/libs/filament/include/filament/ColorGrading.h @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_COLORGRADING_H +#define TNT_FILAMENT_COLORGRADING_H + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +class Engine; +class FColorGrading; + +namespace color { +class ColorSpace; +} + +/** + * ColorGrading is used to transform (either to modify or correct) the colors of the HDR buffer + * rendered by Filament. Color grading transforms are applied after lighting, and after any lens + * effects (bloom for instance), and include tone mapping. + * + * Creation, usage and destruction + * =============================== + * + * A ColorGrading object is created using the ColorGrading::Builder and destroyed by calling + * Engine::destroy(const ColorGrading*). A ColorGrading object is meant to be set on a View. + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::ColorGrading* colorGrading = filament::ColorGrading::Builder() + * .toneMapping(filament::ColorGrading::ToneMapping::ACES) + * .build(*engine); + * + * myView->setColorGrading(colorGrading); + * + * engine->destroy(colorGrading); + * ~~~~~~~~~~~ + * + * Performance + * =========== + * + * Creating a new ColorGrading object may be more expensive than other Filament objects as a + * 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on + * the CPU. + * + * Ordering + * ======== + * + * The various transforms held by ColorGrading are applied in the following order: + * - Exposure + * - Night adaptation + * - White balance + * - Channel mixer + * - Shadows/mid-tones/highlights + * - Slope/offset/power (CDL) + * - Contrast + * - Vibrance + * - Saturation + * - Curves + * - Tone mapping + * - Luminance scaling + * - Gamut mapping + * + * Defaults + * ======== + * + * Here are the default color grading options: + * - Exposure: 0.0 + * - Night adaptation: 0.0 + * - White balance: temperature 0, and tint 0 + * - Channel mixer: red {1,0,0}, green {0,1,0}, blue {0,0,1} + * - Shadows/mid-tones/highlights: shadows {1,1,1,0}, mid-tones {1,1,1,0}, highlights {1,1,1,0}, + * ranges {0,0.333,0.550,1} + * - Slope/offset/power: slope 1.0, offset 0.0, and power 1.0 + * - Contrast: 1.0 + * - Vibrance: 1.0 + * - Saturation: 1.0 + * - Curves: gamma {1,1,1}, midPoint {1,1,1}, and scale {1,1,1} + * - Tone mapping: ACESLegacyToneMapper + * - Luminance scaling: false + * - Gamut mapping: false + * - Output color space: Rec709-sRGB-D65 + * + * @see View + */ +class UTILS_PUBLIC ColorGrading : public FilamentAPI { + struct BuilderDetails; +public: + + enum class QualityLevel : uint8_t { + LOW, + MEDIUM, + HIGH, + ULTRA + }; + + enum class LutFormat : uint8_t { + INTEGER, //!< 10 bits per component + FLOAT, //!< 16 bits per component (10 bits mantissa precision) + }; + + + /** + * List of available tone-mapping operators. + * + * @deprecated Use Builder::toneMapper(ToneMapper*) instead + */ + enum class UTILS_DEPRECATED ToneMapping : uint8_t { + LINEAR = 0, //!< Linear tone mapping (i.e. no tone mapping) + ACES_LEGACY = 1, //!< ACES tone mapping, with a brightness modifier to match Filament's legacy tone mapper + ACES = 2, //!< ACES tone mapping + FILMIC = 3, //!< Filmic tone mapping, modelled after ACES but applied in sRGB space + DISPLAY_RANGE = 4, //!< Tone mapping used to validate/debug scene exposure + }; + + //! Use Builder to construct a ColorGrading object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Sets the quality level of the color grading. When color grading is implemented using + * a 3D LUT, the quality level may impact the resolution and bit depth of the backing + * 3D texture. For instance, a low quality level will use a 16x16x16 10 bit LUT, a medium + * quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit + * LUT, and a ultra quality will use a 64x64x64 16 bit LUT. + * This overrides the values set by format() and dimensions(). + * + * The default quality is medium. + * + * @param qualityLevel The desired quality of the color grading process + * + * @return This Builder, for chaining calls + */ + Builder& quality(QualityLevel qualityLevel) noexcept; + + /** + * When color grading is implemented using a 3D LUT, this sets the texture format of + * of the LUT. This overrides the value set by quality(). + * + * The default is INTEGER + * + * @param format The desired format of the 3D LUT. + * + * @return This Builder, for chaining calls + */ + Builder& format(LutFormat format) noexcept; + + /** + * When color grading is implemented using a 3D LUT, this sets the dimension of the LUT. + * This overrides the value set by quality(). + * + * The default is 32 + * + * @param dim The desired dimension of the LUT. Between 16 and 64. + * + * @return This Builder, for chaining calls + */ + Builder& dimensions(uint8_t dim) noexcept; + + /** + * Selects the tone mapping operator to apply to the HDR color buffer as the last + * operation of the color grading post-processing step. + * + * The default tone mapping operator is ACESLegacyToneMapper. + * + * The specified tone mapper must have a lifecycle that exceeds the lifetime of + * this builder. Since the build(Engine&) method is synchronous, it is safe to + * delete the tone mapper object after that finishes executing. + * + * @param toneMapper The tone mapping operator to apply to the HDR color buffer + * + * @return This Builder, for chaining calls + */ + Builder& toneMapper(ToneMapper const* UTILS_NULLABLE toneMapper) noexcept; + + /** + * Selects the tone mapping operator to apply to the HDR color buffer as the last + * operation of the color grading post-processing step. + * + * The default tone mapping operator is ACES_LEGACY. + * + * @param toneMapping The tone mapping operator to apply to the HDR color buffer + * + * @return This Builder, for chaining calls + * + * @deprecated Use toneMapper(ToneMapper*) instead + */ + UTILS_DEPRECATED + Builder& toneMapping(ToneMapping toneMapping) noexcept; + + /** + * Enables or disables the luminance scaling component (LICH) from the exposure value + * invariant luminance system (EVILS). When this setting is enabled, pixels with high + * chromatic values will roll-off to white to offer a more natural rendering. This step + * also helps avoid undesirable hue skews caused by out of gamut colors clipped + * to the destination color gamut. + * + * When luminance scaling is enabled, tone mapping is performed on the luminance of each + * pixel instead of per-channel. + * + * @param luminanceScaling Enables or disables luminance scaling post-tone mapping + * + * @return This Builder, for chaining calls + */ + Builder& luminanceScaling(bool luminanceScaling) noexcept; + + /** + * Enables or disables gamut mapping to the destination color space's gamut. When gamut + * mapping is turned off, out-of-gamut colors are clipped to the destination's gamut, + * which may produce hue skews (blue skewing to purple, green to yellow, etc.). When + * gamut mapping is enabled, out-of-gamut colors are brought back in gamut by trying to + * preserve the perceived chroma and lightness of the original values. + * + * @param gamutMapping Enables or disables gamut mapping + * + * @return This Builder, for chaining calls + */ + Builder& gamutMapping(bool gamutMapping) noexcept; + + /** + * Adjusts the exposure of this image. The exposure is specified in stops: + * each stop brightens (positive values) or darkens (negative values) the image by + * a factor of 2. This means that an exposure of 3 will brighten the image 8 times + * more than an exposure of 0 (2^3 = 8 and 2^0 = 1). Contrary to the camera's exposure, + * this setting is applied after all post-processing (bloom, etc.) are applied. + * + * @param exposure Value in EV stops. Can be negative, 0, or positive. + * + * @return This Builder, for chaining calls + */ + Builder& exposure(float exposure) noexcept; + + /** + * Controls the amount of night adaptation to replicate a more natural representation of + * low-light conditions as perceived by the human vision system. In low-light conditions, + * peak luminance sensitivity of the eye shifts toward the blue end of the color spectrum: + * darker tones appear brighter, reducing contrast, and colors are blue shifted (the darker + * the more intense the effect). + * + * @param adaptation Amount of adaptation, between 0 (no adaptation) and 1 (full adaptation). + * + * @return This Builder, for chaining calls + */ + Builder& nightAdaptation(float adaptation) noexcept; + + /** + * Adjusts the while balance of the image. This can be used to remove color casts + * and correct the appearance of the white point in the scene, or to alter the + * overall chromaticity of the image for artistic reasons (to make the image appear + * cooler or warmer for instance). + * + * The while balance adjustment is defined with two values: + * - Temperature, to modify the color temperature. This value will modify the colors + * on a blue/yellow axis. Lower values apply a cool color temperature, and higher + * values apply a warm color temperature. The lowest value, -1.0f, is equivalent to + * a temperature of 50,000K. The highest value, 1.0f, is equivalent to a temperature + * of 2,000K. + * - Tint, to modify the colors on a green/magenta axis. The lowest value, -1.0f, will + * apply a strong green cast, and the highest value, 1.0f, will apply a strong magenta + * cast. + * + * Both values are expected to be in the range [-1.0..+1.0]. Values outside of that + * range will be clipped to that range. + * + * @param temperature Modification on the blue/yellow axis, as a value between -1.0 and +1.0. + * @param tint Modification on the green/magenta axis, as a value between -1.0 and +1.0. + * + * @return This Builder, for chaining calls + */ + Builder& whiteBalance(float temperature, float tint) noexcept; + + /** + * The channel mixer adjustment modifies each output color channel using the specified + * mix of the source color channels. + * + * By default each output color channel is set to use 100% of the corresponding source + * channel and 0% of the other channels. For instance, the output red channel is set to + * {1.0, 0.0, 1.0} or 100% red, 0% green and 0% blue. + * + * Each output channel can add or subtract data from the source channel by using values + * in the range [-2.0..+2.0]. Values outside of that range will be clipped to that range. + * + * Using the channel mixer adjustment you can for instance create a monochrome output + * by setting all 3 output channels to the same mix. For instance: {0.4, 0.4, 0.2} for + * all 3 output channels(40% red, 40% green and 20% blue). + * + * More complex mixes can be used to create more complex effects. For instance, here is + * a mix that creates a sepia tone effect: + * - outRed = {0.255, 0.858, 0.087} + * - outGreen = {0.213, 0.715, 0.072} + * - outBlue = {0.170, 0.572, 0.058} + * + * @param outRed The mix of source RGB for the output red channel, between -2.0 and +2.0 + * @param outGreen The mix of source RGB for the output green channel, between -2.0 and +2.0 + * @param outBlue The mix of source RGB for the output blue channel, between -2.0 and +2.0 + * + * @return This Builder, for chaining calls + */ + Builder& channelMixer( + math::float3 outRed, math::float3 outGreen, math::float3 outBlue) noexcept; + + /** + * Adjusts the colors separately in 3 distinct tonal ranges or zones: shadows, mid-tones, + * and highlights. + * + * The tonal zones are by the ranges parameter: the x and y components define the beginning + * and end of the transition from shadows to mid-tones, and the z and w components define + * the beginning and end of the transition from mid-tones to highlights. + * + * A smooth transition is applied between the zones which means for instance that the + * correction color of the shadows range will partially apply to the mid-tones, and the + * other way around. This ensure smooth visual transitions in the final image. + * + * Each correction color is defined as a linear RGB color and a weight. The weight is a + * value (which may be positive or negative) that is added to the linear RGB color before + * mixing. This can be used to darken or brighten the selected tonal range. + * + * Shadows/mid-tones/highlights adjustment are performed linear space. + * + * @param shadows Linear RGB color (.rgb) and weight (.w) to apply to the shadows + * @param midtones Linear RGB color (.rgb) and weight (.w) to apply to the mid-tones + * @param highlights Linear RGB color (.rgb) and weight (.w) to apply to the highlights + * @param ranges Range of the shadows (x and y), and range of the highlights (z and w) + * + * @return This Builder, for chaining calls + */ + Builder& shadowsMidtonesHighlights( + math::float4 shadows, math::float4 midtones, math::float4 highlights, + math::float4 ranges) noexcept; + + /** + * Applies a slope, offset, and power, as defined by the ASC CDL (American Society of + * Cinematographers Color Decision List) to the image. The CDL can be used to adjust the + * colors of different tonal ranges in the image. + * + * The ASC CDL is similar to the lift/gamma/gain controls found in many color grading tools. + * Lift is equivalent to a combination of offset and slope, gain is equivalent to slope, + * and gamma is equivalent to power. + * + * The slope and power values must be strictly positive. Values less than or equal to 0 will + * be clamped to a small positive value, offset can be any positive or negative value. + * + * Version 1.2 of the ASC CDL adds saturation control, which is here provided as a separate + * API. See the saturation() method for more information. + * + * Slope/offset/power adjustments are performed in log space. + * + * @param slope Multiplier of the input color, must be a strictly positive number + * @param offset Added to the input color, can be a negative or positive number, including 0 + * @param power Power exponent of the input color, must be a strictly positive number + * + * @return This Builder, for chaining calls + */ + Builder& slopeOffsetPower(math::float3 slope, math::float3 offset, math::float3 power) noexcept; + + /** + * Adjusts the contrast of the image. Lower values decrease the contrast of the image + * (the tonal range is narrowed), and higher values increase the contrast of the image + * (the tonal range is widened). A value of 1.0 has no effect. + * + * The contrast is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Contrast adjustment is performed in log space. + * + * @param contrast Contrast expansion, between 0.0 and 2.0. 1.0 leaves contrast unaffected + * + * @return This Builder, for chaining calls + */ + Builder& contrast(float contrast) noexcept; + + /** + * Adjusts the saturation of the image based on the input color's saturation level. + * Colors with a high level of saturation are less affected than colors with low saturation + * levels. + * + * Lower vibrance values decrease intensity of the colors present in the image, and + * higher values increase the intensity of the colors in the image. A value of 1.0 has + * no effect. + * + * The vibrance is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Vibrance adjustment is performed in linear space. + * + * @param vibrance Vibrance, between 0.0 and 2.0. 1.0 leaves vibrance unaffected + * + * @return This Builder, for chaining calls + */ + Builder& vibrance(float vibrance) noexcept; + + /** + * Adjusts the saturation of the image. Lower values decrease intensity of the colors + * present in the image, and higher values increase the intensity of the colors in the + * image. A value of 1.0 has no effect. + * + * The saturation is defined as a value in the range [0.0...2.0]. Values outside of that + * range will be clipped to that range. + * + * Saturation adjustment is performed in linear space. + * + * @param saturation Saturation, between 0.0 and 2.0. 1.0 leaves saturation unaffected + * + * @return This Builder, for chaining calls + */ + Builder& saturation(float saturation) noexcept; + + /** + * Applies a curve to each RGB channel of the image. Each curve is defined by 3 values: + * a gamma value applied to the shadows only, a mid-point indicating where shadows stop + * and highlights start, and a scale factor for the highlights. + * + * The gamma and mid-point must be strictly positive values. If they are not, they will be + * clamped to a small positive value. The scale can be any negative of positive value. + * + * Curves are applied in linear space. + * + * @param shadowGamma Power value to apply to the shadows, must be strictly positive + * @param midPoint Mid-point defining where shadows stop and highlights start, must be strictly positive + * @param highlightScale Scale factor for the highlights, can be any negative or positive value + * + * @return This Builder, for chaining calls + */ + Builder& curves(math::float3 shadowGamma, math::float3 midPoint, math::float3 highlightScale) noexcept; + + /** + * Sets the output color space for this ColorGrading object. After all color grading steps + * have been applied, the final color will be converted in the desired color space. + * + * NOTE: Currently the output color space must be one of Rec709-sRGB-D65 or + * Rec709-Linear-D65. Only the transfer function is taken into account. + * + * @param colorSpace The output color space. + * + * @return This Builder, for chaining calls + */ + Builder& outputColorSpace(const color::ColorSpace& colorSpace) noexcept; + + /** + * Creates the ColorGrading object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this ColorGrading with. + * + * @return pointer to the newly created object. + */ + ColorGrading* UTILS_NONNULL build(Engine& engine); + + private: + friend class FColorGrading; + }; + +protected: + // prevent heap allocation + ~ColorGrading() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_COLORGRADING_H diff --git a/package/ios/libs/filament/include/filament/ColorSpace.h b/package/ios/libs/filament/include/filament/ColorSpace.h new file mode 100644 index 00000000..d8890955 --- /dev/null +++ b/package/ios/libs/filament/include/filament/ColorSpace.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_COLOR_SPACE_H +#define TNT_FILAMENT_COLOR_SPACE_H + +#include + +namespace filament::color { + +using namespace math; + +/** + * Holds the chromaticities of a color space's primaries as xy coordinates + * in xyY (Y is assumed to be 1). + */ +struct Primaries { + float2 r; + float2 g; + float2 b; + + bool operator==(const Primaries& rhs) const noexcept { + return r == rhs.r && b == rhs.b && g == rhs.g; + } +}; + +//! Reference white for a color space, defined as the xy coordinates in the xyY space. +using WhitePoint = float2; + +/** + *

Defines the parameters for the ICC parametric curve type 4, as + * defined in ICC.1:2004-10, section 10.15.

+ * + *

The EOTF is of the form:

+ * + * \(\begin{equation} + * Y = \begin{cases}c X + f & X \lt d \\\ + * \left( a X + b \right) ^{g} + e & X \ge d \end{cases} + * \end{equation}\) + * + *

The corresponding OETF is simply the inverse function.

+ * + *

The parameters defined by this class form a valid transfer + * function only if all the following conditions are met:

+ *
    + *
  • No parameter is a NaN
  • + *
  • \(d\) is in the range \([0..1]\)
  • + *
  • The function is not constant
  • + *
  • The function is positive and increasing
  • + *
+ */ +struct TransferFunction { + /** + *

Defines the parameters for the ICC parametric curve type 3, as + * defined in ICC.1:2004-10, section 10.15.

+ * + *

The EOTF is of the form:

+ * + * \(\begin{equation} + * Y = \begin{cases}c X & X \lt d \\\ + * \left( a X + b \right) ^{g} & X \ge d \end{cases} + * \end{equation}\) + * + *

This constructor is equivalent to setting \(e\) and \(f\) to 0.

+ * + * @param a The value of \(a\) in the equation of the EOTF described above + * @param b The value of \(b\) in the equation of the EOTF described above + * @param c The value of \(c\) in the equation of the EOTF described above + * @param d The value of \(d\) in the equation of the EOTF described above + * @param g The value of \(g\) in the equation of the EOTF described above + */ + constexpr TransferFunction( + double a, + double b, + double c, + double d, + double e, + double f, + double g + ) : a(a), + b(b), + c(c), + d(d), + e(e), + f(f), + g(g) { + } + + constexpr TransferFunction( + double a, + double b, + double c, + double d, + double g + ) : TransferFunction(a, b, c, d, 0.0, 0.0, g) { + } + + bool operator==(const TransferFunction& rhs) const noexcept { + return + a == rhs.a && + b == rhs.b && + c == rhs.c && + d == rhs.d && + e == rhs.e && + f == rhs.f && + g == rhs.g; + } + + double a; + double b; + double c; + double d; + double e; + double f; + double g; +}; + +/** + *

A color space in Filament is always an RGB color space. A specific RGB color space + * is defined by the following properties:

+ *
    + *
  • Three chromaticities of the red, green and blue primaries, which + * define the gamut of the color space.
  • + *
  • A white point chromaticity that defines the stimulus to which + * color space values are normalized (also just called "white").
  • + *
  • An opto-electronic transfer function, also called opto-electronic + * conversion function or often, and approximately, gamma function.
  • + *
  • An electro-optical transfer function, also called electo-optical + * conversion function or often, and approximately, gamma function.
  • + *
+ * + *

Primaries and white point chromaticities

+ *

In this implementation, the chromaticity of the primaries and the white + * point of an RGB color space is defined in the CIE xyY color space. This + * color space separates the chromaticity of a color, the x and y components, + * and its luminance, the Y component. Since the primaries and the white + * point have full brightness, the Y component is assumed to be 1 and only + * the x and y components are needed to encode them.

+ * + *

Transfer functions

+ *

A transfer function is a color component conversion function, defined as + * a single variable, monotonic mathematical function. It is applied to each + * individual component of a color. They are used to perform the mapping + * between linear tristimulus values and non-linear electronic signal value.

+ *

The opto-electronic transfer function (OETF or OECF) encodes + * tristimulus values in a scene to a non-linear electronic signal value.

+ */ +class ColorSpace { +public: + constexpr ColorSpace( + const Primaries primaries, + const TransferFunction transferFunction, + const WhitePoint whitePoint + ) : mPrimaries(primaries), + mTransferFunction(transferFunction), + mWhitePoint(whitePoint) { + } + + bool operator==(const ColorSpace& rhs) const noexcept { + return mPrimaries == rhs.mPrimaries && + mTransferFunction == rhs.mTransferFunction && + mWhitePoint == rhs.mWhitePoint; + } + + constexpr const Primaries& getPrimaries() const { return mPrimaries; } + constexpr const TransferFunction& getTransferFunction() const { return mTransferFunction; } + constexpr const WhitePoint& getWhitePoint() const { return mWhitePoint; } + +private: + Primaries mPrimaries; + TransferFunction mTransferFunction; + WhitePoint mWhitePoint; +}; + +/** + * Intermediate class used when building a color space using the "-" syntax: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * // Declares a "linear sRGB" color space. + * ColorSpace myColorSpace = Rec709-Linear-D65; + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class PartialColorSpace { +public: + constexpr ColorSpace operator-(const WhitePoint& whitePoint) const { + return { mPrimaries, mTransferFunction, whitePoint }; + } + +private: + constexpr PartialColorSpace( + const Primaries primaries, + const TransferFunction transferFunction + ) : mPrimaries(primaries), + mTransferFunction(transferFunction) { + } + + Primaries mPrimaries; + TransferFunction mTransferFunction; + + friend class Gamut; +}; + +/** + * Defines the chromaticities of the primaries for a color space. The chromaticities + * are expressed as three pairs of xy coordinates (in xyY) for the red, green, and blue + * chromaticities. + */ +class Gamut { +public: + constexpr explicit Gamut(const Primaries primaries) : mPrimaries(primaries) { + } + + constexpr Gamut(float2 r, float2 g, float2 b) : Gamut(Primaries{ r, g, b }) { + } + + constexpr PartialColorSpace operator-(const TransferFunction& transferFunction) const { + return { mPrimaries, transferFunction }; + } + + constexpr const Primaries& getPrimaries() const { return mPrimaries; } + +private: + Primaries mPrimaries; +}; + +//! Rec.709 color gamut, used in the sRGB and DisplayP3 color spaces. +constexpr Gamut Rec709 = {{ 0.640f, 0.330f }, + { 0.300f, 0.600f }, + { 0.150f, 0.060f }}; + +//! Linear transfer function. +constexpr TransferFunction Linear = { 1.0, 0.0, 0.0, 0.0, 1.0 }; + +//! sRGB transfer function. +constexpr TransferFunction sRGB = { 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045, 2.4 }; + +//! Standard CIE 1931 2° illuminant D65. This illuminant has a color temperature of 6504K. +constexpr WhitePoint D65 = { 0.31271f, 0.32902f }; + +} // namespace filament::color + +#endif // TNT_FILAMENT_COLOR_SPACE_H diff --git a/package/ios/libs/filament/include/filament/DebugRegistry.h b/package/ios/libs/filament/include/filament/DebugRegistry.h new file mode 100644 index 00000000..d5e1d8e9 --- /dev/null +++ b/package/ios/libs/filament/include/filament/DebugRegistry.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_DEBUGREGISTRY_H +#define TNT_FILAMENT_DEBUGREGISTRY_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * A registry of runtime properties used exclusively for debugging + * + * Filament exposes a few properties that can be queried and set, which control certain debugging + * features of the engine. These properties can be set at runtime at anytime. + * + */ +class UTILS_PUBLIC DebugRegistry : public FilamentAPI { +public: + + /** + * Queries whether a property exists + * @param name The name of the property to query + * @return true if the property exists, false otherwise + */ + bool hasProperty(const char* UTILS_NONNULL name) const noexcept; + + /** + * Queries the address of a property's data from its name + * @param name Name of the property we want the data address of + * @return Address of the data of the \p name property + * @{ + */ + void* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name); + + void const* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) const noexcept; + + template + inline T* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) { + return static_cast(getPropertyAddress(name)); + } + + template + inline T const* UTILS_NULLABLE getPropertyAddress(const char* UTILS_NONNULL name) const noexcept { + return static_cast(getPropertyAddress(name)); + } + + template + inline bool getPropertyAddress(const char* UTILS_NONNULL name, + T* UTILS_NULLABLE* UTILS_NONNULL p) { + *p = getPropertyAddress(name); + return *p != nullptr; + } + + template + inline bool getPropertyAddress(const char* UTILS_NONNULL name, + T* const UTILS_NULLABLE* UTILS_NONNULL p) const noexcept { + *p = getPropertyAddress(name); + return *p != nullptr; + } + /** @}*/ + + /** + * Set the value of a property + * @param name Name of the property to set the value of + * @param v Value to set + * @return true if the operation was successful, false otherwise. + * @{ + */ + bool setProperty(const char* UTILS_NONNULL name, bool v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, int v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, float v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float2 v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float3 v) noexcept; + bool setProperty(const char* UTILS_NONNULL name, math::float4 v) noexcept; + /** @}*/ + + /** + * Get the value of a property + * @param name Name of the property to get the value of + * @param v A pointer to a variable which will hold the result + * @return true if the call was successful and \p v was updated + * @{ + */ + bool getProperty(const char* UTILS_NONNULL name, bool* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, int* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, float* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float2* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float3* UTILS_NONNULL v) const noexcept; + bool getProperty(const char* UTILS_NONNULL name, math::float4* UTILS_NONNULL v) const noexcept; + /** @}*/ + + struct DataSource { + void const* UTILS_NULLABLE data; + size_t count; + }; + + DataSource getDataSource(const char* UTILS_NONNULL name) const noexcept; + + struct FrameHistory { + using duration_ms = float; + duration_ms target{}; + duration_ms targetWithHeadroom{}; + duration_ms frameTime{}; + duration_ms frameTimeDenoised{}; + float scale = 1.0f; + float pid_e = 0.0f; + float pid_i = 0.0f; + float pid_d = 0.0f; + }; + +protected: + // prevent heap allocation + ~DebugRegistry() = default; +}; + + +} // namespace filament + +#endif /* TNT_FILAMENT_DEBUGREGISTRY_H */ diff --git a/package/ios/libs/filament/include/filament/Engine.h b/package/ios/libs/filament/include/filament/Engine.h new file mode 100644 index 00000000..493573cc --- /dev/null +++ b/package/ios/libs/filament/include/filament/Engine.h @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_ENGINE_H +#define TNT_FILAMENT_ENGINE_H + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace utils { +class Entity; +class EntityManager; +class JobSystem; +} // namespace utils + +namespace filament { + +class BufferObject; +class Camera; +class ColorGrading; +class DebugRegistry; +class Fence; +class IndexBuffer; +class SkinningBuffer; +class IndirectLight; +class Material; +class MaterialInstance; +class MorphTargetBuffer; +class Renderer; +class RenderTarget; +class Scene; +class Skybox; +class Stream; +class SwapChain; +class Texture; +class VertexBuffer; +class View; +class InstanceBuffer; + +class LightManager; +class RenderableManager; +class TransformManager; + +#ifndef FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB +# define FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB 3 +#endif + +#ifndef FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB +# define FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB 2 +#endif + +#ifndef FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB +# define FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB 1 +#endif + +#ifndef FILAMENT_COMMAND_BUFFER_SIZE_IN_MB +# define FILAMENT_COMMAND_BUFFER_SIZE_IN_MB (FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB * 3) +#endif + +/** + * Engine is filament's main entry-point. + * + * An Engine instance main function is to keep track of all resources created by the user and + * manage the rendering thread as well as the hardware renderer. + * + * To use filament, an Engine instance must be created first: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Engine essentially represents (or is associated to) a hardware context + * (e.g. an OpenGL ES context). + * + * Rendering typically happens in an operating system's window (which can be full screen), such + * window is managed by a filament.Renderer. + * + * A typical filament render loop looks like this: + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * Renderer* renderer = engine->createRenderer(); + * Scene* scene = engine->createScene(); + * View* view = engine->createView(); + * + * view->setScene(scene); + * + * do { + * // typically we wait for VSYNC and user input events + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } while (!quit); + * + * engine->destroy(view); + * engine->destroy(scene); + * engine->destroy(renderer); + * engine->destroy(swapChain); + * Engine::destroy(&engine); // clears engine* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Resource Tracking + * ================= + * + * Each Engine instance keeps track of all objects created by the user, such as vertex and index + * buffers, lights, cameras, etc... + * The user is expected to free those resources, however, leaked resources are freed when the + * engine instance is destroyed and a warning is emitted in the console. + * + * Thread safety + * ============= + * + * An Engine instance is not thread-safe. The implementation makes no attempt to synchronize + * calls to an Engine instance methods. + * If multi-threading is needed, synchronization must be external. + * + * Multi-threading + * =============== + * + * When created, the Engine instance starts a render thread as well as multiple worker threads, + * these threads have an elevated priority appropriate for rendering, based on the platform's + * best practices. The number of worker threads depends on the platform and is automatically + * chosen for best performance. + * + * On platforms with asymmetric cores (e.g. ARM's Big.Little), Engine makes some educated guesses + * as to which cores to use for the render thread and worker threads. For example, it'll try to + * keep an OpenGL ES thread on a Big core. + * + * Swap Chains + * =========== + * + * A swap chain represents an Operating System's *native* renderable surface. Typically it's a window + * or a view. Because a SwapChain is initialized from a native object, it is given to filament + * as a `void*`, which must be of the proper type for each platform filament is running on. + * + * @see SwapChain + * + * + * @see Renderer + */ +class UTILS_PUBLIC Engine { + struct BuilderDetails; +public: + using Platform = backend::Platform; + using Backend = backend::Backend; + using DriverConfig = backend::Platform::DriverConfig; + using FeatureLevel = backend::FeatureLevel; + using StereoscopicType = backend::StereoscopicType; + + /** + * Config is used to define the memory footprint used by the engine, such as the + * command buffer size. Config can be used to customize engine requirements based + * on the applications needs. + * + * .perRenderPassArenaSizeMB (default: 3 MiB) + * +--------------------------+ + * | | + * | .perFrameCommandsSizeMB | + * | (default 2 MiB) | + * | | + * +--------------------------+ + * | (froxel, etc...) | + * +--------------------------+ + * + * + * .commandBufferSizeMB (default 3MiB) + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * | .minCommandBufferSizeMB | + * +--------------------------+ + * : : + * : : + * + */ + struct Config { + /** + * Size in MiB of the low-level command buffer arena. + * + * Each new command buffer is allocated from here. If this buffer is too small the program + * might terminate or rendering errors might occur. + * + * This is typically set to minCommandBufferSizeMB * 3, so that up to 3 frames can be + * batched-up at once. + * + * This value affects the application's memory usage. + */ + uint32_t commandBufferSizeMB = FILAMENT_COMMAND_BUFFER_SIZE_IN_MB; + + + /** + * Size in MiB of the per-frame data arena. + * + * This is the main arena used for allocations when preparing a frame. + * e.g.: Froxel data and high-level commands are allocated from this arena. + * + * If this size is too small, the program will abort on debug builds and have undefined + * behavior otherwise. + * + * This value affects the application's memory usage. + */ + uint32_t perRenderPassArenaSizeMB = FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB; + + + /** + * Size in MiB of the backend's handle arena. + * + * Backends will fallback to slower heap-based allocations when running out of space and + * log this condition. + * + * If 0, then the default value for the given platform is used + * + * This value affects the application's memory usage. + */ + uint32_t driverHandleArenaSizeMB = 0; + + + /** + * Minimum size in MiB of a low-level command buffer. + * + * This is how much space is guaranteed to be available for low-level commands when a new + * buffer is allocated. If this is too small, the engine might have to stall to wait for + * more space to become available, this situation is logged. + * + * This value does not affect the application's memory usage. + */ + uint32_t minCommandBufferSizeMB = FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB; + + + /** + * Size in MiB of the per-frame high level command buffer. + * + * This buffer is related to the number of draw calls achievable within a frame, if it is + * too small, the program will abort on debug builds and have undefined behavior otherwise. + * + * It is allocated from the 'per-render-pass arena' above. Make sure that at least 1 MiB is + * left in the per-render-pass arena when deciding the size of this buffer. + * + * This value does not affect the application's memory usage. + */ + uint32_t perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB; + + /** + * Number of threads to use in Engine's JobSystem. + * + * Engine uses a utils::JobSystem to carry out paralleization of Engine workloads. This + * value sets the number of threads allocated for JobSystem. Configuring this value can be + * helpful in CPU-constrained environments where too many threads can cause contention of + * CPU and reduce performance. + * + * The default value is 0, which implies that the Engine will use a heuristic to determine + * the number of threads to use. + */ + uint32_t jobSystemThreadCount = 0; + + /* + * Number of most-recently destroyed textures to track for use-after-free. + * + * This will cause the backend to throw an exception when a texture is freed but still bound + * to a SamplerGroup and used in a draw call. 0 disables completely. + * + * Currently only respected by the Metal backend. + */ + size_t textureUseAfterFreePoolSize = 0; + + /* + * The type of technique for stereoscopic rendering. + * + * This setting determines the algorithm used when stereoscopic rendering is enabled. This + * decision applies to the entire Engine for the lifetime of the Engine. E.g., multiple + * Views created from the Engine must use the same stereoscopic type. + * + * Each view can enable stereoscopic rendering via the StereoscopicOptions::enable flag. + * + * @see View::setStereoscopicOptions + */ + StereoscopicType stereoscopicType = StereoscopicType::INSTANCED; + + /* + * The number of eyes to render when stereoscopic rendering is enabled. Supported values are + * between 1 and Engine::getMaxStereoscopicEyes() (inclusive). + * + * @see View::setStereoscopicOptions + * @see Engine::getMaxStereoscopicEyes + */ + uint8_t stereoscopicEyeCount = 2; + + /* + * Size in MiB of the frame graph texture cache. This should be adjusted based on the + * size of used render targets (typically the screen). + */ + uint32_t resourceAllocatorCacheSizeMB = 64; + + /* + * This value determines for how many frames are texture entries kept in the cache. + * The default value of 30 corresponds to about half a second at 60 fps. + */ + uint32_t resourceAllocatorCacheMaxAge = 30; + }; + + +#if UTILS_HAS_THREADING + using CreateCallback = void(void* UTILS_NULLABLE user, void* UTILS_NONNULL token); +#endif + + /** + * Engine::Builder is used to create a new filament Engine. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + friend class FEngine; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * @param backend Which driver backend to use + * @return A reference to this Builder for chaining calls. + */ + Builder& backend(Backend backend) noexcept; + + /** + * @param platform A pointer to an object that implements Platform. If this is + * provided, then this object is used to create the hardware context + * and expose platform features to it. + * + * If not provided (or nullptr is used), an appropriate Platform + * is created automatically. + * + * All methods of this interface are called from filament's + * render thread, which is different from the main thread. + * + * The lifetime of \p platform must exceed the lifetime of + * the Engine object. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& platform(Platform* UTILS_NULLABLE platform) noexcept; + + /** + * @param config A pointer to optional parameters to specify memory size + * configuration options. If nullptr, then defaults used. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& config(const Config* UTILS_NULLABLE config) noexcept; + + /** + * @param sharedContext A platform-dependant context used as a shared context + * when creating filament's internal context. + * + * @return A reference to this Builder for chaining calls. + */ + Builder& sharedContext(void* UTILS_NULLABLE sharedContext) noexcept; + + /** + * @param featureLevel The feature level at which initialize Filament. + * @return A reference to this Builder for chaining calls. + */ + Builder& featureLevel(FeatureLevel featureLevel) noexcept; + +#if UTILS_HAS_THREADING + /** + * Creates the filament Engine asynchronously. + * + * @param callback Callback called once the engine is initialized and it is safe to + * call Engine::getEngine(). + */ + void build(utils::Invocable&& callback) const; +#endif + + /** + * Creates an instance of Engine. + * + * @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be + * created. + * nullptr if the GPU driver couldn't be initialized, for instance if it doesn't + * support the right version of OpenGL or OpenGL ES. + * + * @exception utils::PostConditionPanic can be thrown if there isn't enough memory to + * allocate the command buffer. If exceptions are disabled, this condition if + * fatal and this function will abort. + */ + Engine* UTILS_NULLABLE build() const; + }; + + /** + * Backward compatibility helper to create an Engine. + * @see Builder + */ + static inline Engine* UTILS_NULLABLE create(Backend backend = Backend::DEFAULT, + Platform* UTILS_NULLABLE platform = nullptr, + void* UTILS_NULLABLE sharedContext = nullptr, + const Config* UTILS_NULLABLE config = nullptr) { + return Engine::Builder() + .backend(backend) + .platform(platform) + .sharedContext(sharedContext) + .config(config) + .build(); + } + + +#if UTILS_HAS_THREADING + /** + * Backward compatibility helper to create an Engine asynchronously. + * @see Builder + */ + static inline void createAsync(CreateCallback callback, + void* UTILS_NULLABLE user, + Backend backend = Backend::DEFAULT, + Platform* UTILS_NULLABLE platform = nullptr, + void* UTILS_NULLABLE sharedContext = nullptr, + const Config* UTILS_NULLABLE config = nullptr) { + Engine::Builder() + .backend(backend) + .platform(platform) + .sharedContext(sharedContext) + .config(config) + .build([callback, user](void* UTILS_NONNULL token) { + callback(user, token); + }); + } + + /** + * Retrieve an Engine* from createAsync(). This must be called from the same thread than + * Engine::createAsync() was called from. + * + * @param token An opaque token given in the createAsync() callback function. + * + * @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be created. + * + * @exception utils::PostConditionPanic can be thrown if there isn't enough memory to + * allocate the command buffer. If exceptions are disabled, this condition if fatal and + * this function will abort. + */ + static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token); +#endif + + + /** + * Destroy the Engine instance and all associated resources. + * + * Engine.destroy() should be called last and after all other resources have been destroyed, + * it ensures all filament resources are freed. + * + * Destroy performs the following tasks: + * 1. Destroy all internal software and hardware resources. + * 2. Free all user allocated resources that are not already destroyed and logs a warning. + * This indicates a "leak" in the user's code. + * 3. Terminate the rendering engine's thread. + * + * @param engine A pointer to the filament.Engine* to be destroyed. + * \p engine is cleared upon return. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * Engine::destroy(&engine); // clears engine* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \remark + * This method is thread-safe. + */ + static void destroy(Engine* UTILS_NULLABLE* UTILS_NULLABLE engine); + + /** + * Destroy the Engine instance and all associated resources. + * + * Engine.destroy() should be called last and after all other resources have been destroyed, + * it ensures all filament resources are freed. + * + * Destroy performs the following tasks: + * 1. Destroy all internal software and hardware resources. + * 2. Free all user allocated resources that are not already destroyed and logs a warning. + * This indicates a "leak" in the user's code. + * 3. Terminate the rendering engine's thread. + * + * @param engine A pointer to the filament.Engine to be destroyed. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * Engine::destroy(engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \remark + * This method is thread-safe. + */ + static void destroy(Engine* UTILS_NULLABLE engine); + + /** + * Query the feature level supported by the selected backend. + * + * A specific feature level needs to be set before the corresponding features can be used. + * + * @return FeatureLevel supported the selected backend. + * @see setActiveFeatureLevel + */ + FeatureLevel getSupportedFeatureLevel() const noexcept; + + /** + * Activate all features of a given feature level. If an explicit feature level is not specified + * at Engine initialization time via Builder::featureLevel, the default feature level is + * FeatureLevel::FEATURE_LEVEL_0 on devices not compatible with GLES 3.0; otherwise, the default + * is FeatureLevel::FEATURE_LEVEL_1. The selected feature level must not be higher than the + * value returned by getActiveFeatureLevel() and it's not possible lower the active feature + * level. Additionally, it is not possible to modify the feature level at all if the Engine was + * initialized at FeatureLevel::FEATURE_LEVEL_0. + * + * @param featureLevel the feature level to activate. If featureLevel is lower than + * getActiveFeatureLevel(), the current (higher) feature level is kept. If + * featureLevel is higher than getSupportedFeatureLevel(), or if the engine + * was initialized at feature level 0, an exception is thrown, or the + * program is terminated if exceptions are disabled. + * + * @return the active feature level. + * + * @see Builder::featureLevel + * @see getSupportedFeatureLevel + * @see getActiveFeatureLevel + */ + FeatureLevel setActiveFeatureLevel(FeatureLevel featureLevel); + + /** + * Returns the currently active feature level. + * @return currently active feature level + * @see getSupportedFeatureLevel + * @see setActiveFeatureLevel + */ + FeatureLevel getActiveFeatureLevel() const noexcept; + + /** + * Queries the maximum number of GPU instances that Filament creates when automatic instancing + * is enabled. This value is also the limit for the number of transforms that can be stored in + * an InstanceBuffer. This value may depend on the device and platform, but will remain constant + * during the lifetime of this Engine. + * + * This value does not apply when using the instances(size_t) method on + * RenderableManager::Builder. + * + * @return the number of max automatic instances + * @see setAutomaticInstancingEnabled + * @see RenderableManager::Builder::instances(size_t) + * @see RenderableManager::Builder::instances(size_t, InstanceBuffer*) + */ + size_t getMaxAutomaticInstances() const noexcept; + + /** + * Queries the device and platform for support of the given stereoscopic type. + * + * @return true if the given stereo rendering is supported, false otherwise + * @see View::setStereoscopicOptions + */ + bool isStereoSupported(StereoscopicType stereoscopicType) const noexcept; + + /** + * Retrieves the configuration settings of this Engine. + * + * This method returns the configuration object that was supplied to the Engine's + * Builder::config method during the creation of this Engine. If the Builder::config method was + * not explicitly called (or called with nullptr), this method returns the default configuration + * settings. + * + * @return a Config object with this Engine's configuration + * @see Builder::config + */ + const Config& getConfig() const noexcept; + + /** + * Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of + * eyes rendered is set at Engine creation time with the Engine::Config::stereoscopicEyeCount + * setting. + * + * @return the max number of stereoscopic eyes supported + * @see Engine::Config::stereoscopicEyeCount + */ + static size_t getMaxStereoscopicEyes() noexcept; + + /** + * @return EntityManager used by filament + */ + utils::EntityManager& getEntityManager() noexcept; + + /** + * @return RenderableManager reference + */ + RenderableManager& getRenderableManager() noexcept; + + /** + * @return LightManager reference + */ + LightManager& getLightManager() noexcept; + + /** + * @return TransformManager reference + */ + TransformManager& getTransformManager() noexcept; + + /** + * Helper to enable accurate translations. + * If you need this Engine to handle a very large world space, one way to achieve this + * automatically is to enable accurate translations in the TransformManager. This helper + * provides a convenient way of doing that. + * This is typically called once just after creating the Engine. + */ + void enableAccurateTranslations() noexcept; + + /** + * Enables or disables automatic instancing of render primitives. Instancing of render + * primitives can greatly reduce CPU overhead but requires the instanced primitives to be + * identical (i.e. use the same geometry) and use the same MaterialInstance. If it is known + * that the scene doesn't contain any identical primitives, automatic instancing can have some + * overhead and it is then best to disable it. + * + * Disabled by default. + * + * @param enable true to enable, false to disable automatic instancing. + * + * @see RenderableManager + * @see MaterialInstance + */ + void setAutomaticInstancingEnabled(bool enable) noexcept; + + /** + * @return true if automatic instancing is enabled, false otherwise. + * @see setAutomaticInstancingEnabled + */ + bool isAutomaticInstancingEnabled() const noexcept; + + /** + * Creates a SwapChain from the given Operating System's native window handle. + * + * @param nativeWindow An opaque native window handle. e.g.: on Android this is an + * `ANativeWindow*`. + * @param flags One or more configuration flags as defined in `SwapChain`. + * + * @return A pointer to the newly created SwapChain. + * + * @see Renderer.beginFrame() + */ + SwapChain* UTILS_NONNULL createSwapChain(void* UTILS_NULLABLE nativeWindow, uint64_t flags = 0) noexcept; + + + /** + * Creates a headless SwapChain. + * + * @param width Width of the drawing buffer in pixels. + * @param height Height of the drawing buffer in pixels. + * @param flags One or more configuration flags as defined in `SwapChain`. + * + * @return A pointer to the newly created SwapChain. + * + * @see Renderer.beginFrame() + */ + SwapChain* UTILS_NONNULL createSwapChain(uint32_t width, uint32_t height, uint64_t flags = 0) noexcept; + + /** + * Creates a renderer associated to this engine. + * + * A Renderer is intended to map to a *window* on screen. + * + * @return A pointer to the newly created Renderer. + */ + Renderer* UTILS_NONNULL createRenderer() noexcept; + + /** + * Creates a View. + * + * @return A pointer to the newly created View. + */ + View* UTILS_NONNULL createView() noexcept; + + /** + * Creates a Scene. + * + * @return A pointer to the newly created Scene. + */ + Scene* UTILS_NONNULL createScene() noexcept; + + /** + * Creates a Camera component. + * + * @param entity Entity to add the camera component to. + * @return A pointer to the newly created Camera. + */ + Camera* UTILS_NONNULL createCamera(utils::Entity entity) noexcept; + + /** + * Returns the Camera component of the given entity. + * + * @param entity An entity. + * @return A pointer to the Camera component for this entity or nullptr if the entity didn't + * have a Camera component. The pointer is valid until destroyCameraComponent() + * is called or the entity itself is destroyed. + */ + Camera* UTILS_NULLABLE getCameraComponent(utils::Entity entity) noexcept; + + /** + * Destroys the Camera component associated with the given entity. + * + * @param entity An entity. + */ + void destroyCameraComponent(utils::Entity entity) noexcept; + + /** + * Creates a Fence. + * + * @return A pointer to the newly created Fence. + */ + Fence* UTILS_NONNULL createFence() noexcept; + + bool destroy(const BufferObject* UTILS_NULLABLE p); //!< Destroys a BufferObject object. + bool destroy(const VertexBuffer* UTILS_NULLABLE p); //!< Destroys an VertexBuffer object. + bool destroy(const Fence* UTILS_NULLABLE p); //!< Destroys a Fence object. + bool destroy(const IndexBuffer* UTILS_NULLABLE p); //!< Destroys an IndexBuffer object. + bool destroy(const SkinningBuffer* UTILS_NULLABLE p); //!< Destroys a SkinningBuffer object. + bool destroy(const MorphTargetBuffer* UTILS_NULLABLE p); //!< Destroys a MorphTargetBuffer object. + bool destroy(const IndirectLight* UTILS_NULLABLE p); //!< Destroys an IndirectLight object. + + /** + * Destroys a Material object + * @param p the material object to destroy + * @attention All MaterialInstance of the specified material must be destroyed before + * destroying it. + * @exception utils::PreConditionPanic is thrown if some MaterialInstances remain. + * no-op if exceptions are disabled and some MaterialInstances remain. + */ + bool destroy(const Material* UTILS_NULLABLE p); + bool destroy(const MaterialInstance* UTILS_NULLABLE p); //!< Destroys a MaterialInstance object. + bool destroy(const Renderer* UTILS_NULLABLE p); //!< Destroys a Renderer object. + bool destroy(const Scene* UTILS_NULLABLE p); //!< Destroys a Scene object. + bool destroy(const Skybox* UTILS_NULLABLE p); //!< Destroys a SkyBox object. + bool destroy(const ColorGrading* UTILS_NULLABLE p); //!< Destroys a ColorGrading object. + bool destroy(const SwapChain* UTILS_NULLABLE p); //!< Destroys a SwapChain object. + bool destroy(const Stream* UTILS_NULLABLE p); //!< Destroys a Stream object. + bool destroy(const Texture* UTILS_NULLABLE p); //!< Destroys a Texture object. + bool destroy(const RenderTarget* UTILS_NULLABLE p); //!< Destroys a RenderTarget object. + bool destroy(const View* UTILS_NULLABLE p); //!< Destroys a View object. + bool destroy(const InstanceBuffer* UTILS_NULLABLE p); //!< Destroys an InstanceBuffer object. + void destroy(utils::Entity e); //!< Destroys all filament-known components from this entity + + bool isValid(const BufferObject* UTILS_NULLABLE p); //!< Tells whether a BufferObject object is valid + bool isValid(const VertexBuffer* UTILS_NULLABLE p); //!< Tells whether an VertexBuffer object is valid + bool isValid(const Fence* UTILS_NULLABLE p); //!< Tells whether a Fence object is valid + bool isValid(const IndexBuffer* UTILS_NULLABLE p); //!< Tells whether an IndexBuffer object is valid + bool isValid(const SkinningBuffer* UTILS_NULLABLE p); //!< Tells whether a SkinningBuffer object is valid + bool isValid(const MorphTargetBuffer* UTILS_NULLABLE p); //!< Tells whether a MorphTargetBuffer object is valid + bool isValid(const IndirectLight* UTILS_NULLABLE p); //!< Tells whether an IndirectLight object is valid + bool isValid(const Material* UTILS_NULLABLE p); //!< Tells whether an IndirectLight object is valid + bool isValid(const Renderer* UTILS_NULLABLE p); //!< Tells whether a Renderer object is valid + bool isValid(const Scene* UTILS_NULLABLE p); //!< Tells whether a Scene object is valid + bool isValid(const Skybox* UTILS_NULLABLE p); //!< Tells whether a SkyBox object is valid + bool isValid(const ColorGrading* UTILS_NULLABLE p); //!< Tells whether a ColorGrading object is valid + bool isValid(const SwapChain* UTILS_NULLABLE p); //!< Tells whether a SwapChain object is valid + bool isValid(const Stream* UTILS_NULLABLE p); //!< Tells whether a Stream object is valid + bool isValid(const Texture* UTILS_NULLABLE p); //!< Tells whether a Texture object is valid + bool isValid(const RenderTarget* UTILS_NULLABLE p); //!< Tells whether a RenderTarget object is valid + bool isValid(const View* UTILS_NULLABLE p); //!< Tells whether a View object is valid + bool isValid(const InstanceBuffer* UTILS_NULLABLE p); //!< Tells whether an InstanceBuffer object is valid + + /** + * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until + * all commands to this point are executed. Note that does guarantee that the + * hardware is actually finished. + * + *

This is typically used right after destroying the SwapChain, + * in cases where a guarantee about the SwapChain destruction is needed in a + * timely fashion, such as when responding to Android's + * android.view.SurfaceHolder.Callback.surfaceDestroyed

+ */ + void flushAndWait(); + + /** + * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait + * for commands to be either executed or the hardware finished. + * + *

This is typically used after creating a lot of objects to start draining the command + * queue which has a limited size.

+ */ + void flush(); + + /** + * Drains the user callback message queue and immediately execute all pending callbacks. + * + *

Typically this should be called once per frame right after the application's vsync tick, + * and typically just before computing parameters (e.g. object positions) for the next frame. + * This is useful because otherwise callbacks will be executed by filament at a later time, + * which may increase latency in certain applications.

+ */ + void pumpMessageQueues(); + + /** + * Returns the default Material. + * + * The default material is 80% white and uses the Material.Shading.LIT shading. + * + * @return A pointer to the default Material instance (a singleton). + */ + Material const* UTILS_NONNULL getDefaultMaterial() const noexcept; + + /** + * Returns the resolved backend. + */ + Backend getBackend() const noexcept; + + /** + * Returns the Platform object that belongs to this Engine. + * + * When Engine::create is called with no platform argument, Filament creates an appropriate + * Platform subclass automatically. The specific subclass created depends on the backend and + * OS. For example, when the OpenGL backend is used, the Platform object will be a descendant of + * OpenGLPlatform. + * + * dynamic_cast should be used to cast the returned Platform object into a specific subclass. + * Note that RTTI must be available to use dynamic_cast. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Platform* platform = engine->getPlatform(); + * // static_cast also works, but more dangerous. + * SpecificPlatform* specificPlatform = dynamic_cast(platform); + * specificPlatform->platformSpecificMethod(); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * When a custom Platform is passed to Engine::create, Filament will use it instead, and this + * method will return it. + * + * @return A pointer to the Platform object that was provided to Engine::create, or the + * Filament-created one. + */ + Platform* UTILS_NULLABLE getPlatform() const noexcept; + + /** + * Allocate a small amount of memory directly in the command stream. The allocated memory is + * guaranteed to be preserved until the current command buffer is executed + * + * @param size size to allocate in bytes. This should be small (e.g. < 1 KB) + * @param alignment alignment requested + * @return a pointer to the allocated buffer or nullptr if no memory was available. + * + * @note there is no need to destroy this buffer, it will be freed automatically when + * the current command buffer is executed. + */ + void* UTILS_NULLABLE streamAlloc(size_t size, size_t alignment = alignof(double)) noexcept; + + /** + * Invokes one iteration of the render loop, used only on single-threaded platforms. + * + * This should be called every time the windowing system needs to paint (e.g. at 60 Hz). + */ + void execute(); + + /** + * Retrieves the job system that the Engine has ownership over. + * + * @return JobSystem used by filament + */ + utils::JobSystem& getJobSystem() noexcept; + +#if defined(__EMSCRIPTEN__) + /** + * WebGL only: Tells the driver to reset any internal state tracking if necessary. + * + * This is only useful when integrating an external renderer into Filament on platforms + * like WebGL, where share contexts do not exist. Filament keeps track of the GL + * state it has set (like which texture is bound), and does not re-set that state if + * it does not think it needs to. However, if an external renderer has set different + * state in the mean time, Filament will use that new state unknowingly. + * + * If you are in this situation, call this function - ideally only once per frame, + * immediately after calling Engine::execute(). + */ + void resetBackendState() noexcept; +#endif + + DebugRegistry& getDebugRegistry() noexcept; + +protected: + //! \privatesection + Engine() noexcept = default; + ~Engine() = default; + +public: + //! \privatesection + Engine(Engine const&) = delete; + Engine(Engine&&) = delete; + Engine& operator=(Engine const&) = delete; + Engine& operator=(Engine&&) = delete; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_ENGINE_H diff --git a/package/ios/libs/filament/include/filament/Exposure.h b/package/ios/libs/filament/include/filament/Exposure.h new file mode 100644 index 00000000..a1e545f7 --- /dev/null +++ b/package/ios/libs/filament/include/filament/Exposure.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_EXPOSURE_H +#define TNT_FILAMENT_EXPOSURE_H + +#include + +namespace filament { + +class Camera; + +/** + * A series of utilities to compute exposure, exposure value at ISO 100 (EV100), + * luminance and illuminance using a physically-based camera model. + */ +namespace Exposure { + +/** + * Returns the exposure value (EV at ISO 100) of the specified camera. + */ +UTILS_PUBLIC +float ev100(const Camera& camera) noexcept; + +/** + * Returns the exposure value (EV at ISO 100) of the specified exposure parameters. + */ +UTILS_PUBLIC +float ev100(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Returns the exposure value (EV at ISO 100) for the given average luminance (in @f$ \frac{cd}{m^2} @f$). + */ +UTILS_PUBLIC +float ev100FromLuminance(float luminance) noexcept; + +/** +* Returns the exposure value (EV at ISO 100) for the given illuminance (in lux). +*/ +UTILS_PUBLIC +float ev100FromIlluminance(float illuminance) noexcept; + +/** + * Returns the photometric exposure for the specified camera. + */ +UTILS_PUBLIC +float exposure(const Camera& camera) noexcept; + +/** + * Returns the photometric exposure for the specified exposure parameters. + * This function is equivalent to calling `exposure(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float exposure(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Returns the photometric exposure for the given EV100. + */ +UTILS_PUBLIC +float exposure(float ev100) noexcept; + +/** + * Returns the incident luminance in @f$ \frac{cd}{m^2} @f$ for the specified camera acting as a spot meter. + */ +UTILS_PUBLIC +float luminance(const Camera& camera) noexcept; + +/** + * Returns the incident luminance in @f$ \frac{cd}{m^2} @f$ for the specified exposure parameters of + * a camera acting as a spot meter. + * This function is equivalent to calling `luminance(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float luminance(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Converts the specified EV100 to luminance in @f$ \frac{cd}{m^2} @f$. + * EV100 is not a measure of luminance, but an EV100 can be used to denote a + * luminance for which a camera would use said EV100 to obtain the nominally + * correct exposure + */ +UTILS_PUBLIC +float luminance(float ev100) noexcept; + +/** + * Returns the illuminance in lux for the specified camera acting as an incident light meter. + */ +UTILS_PUBLIC +float illuminance(const Camera& camera) noexcept; + +/** + * Returns the illuminance in lux for the specified exposure parameters of + * a camera acting as an incident light meter. + * This function is equivalent to calling `illuminance(ev100(aperture, shutterSpeed, sensitivity))` + * but is slightly faster and offers higher precision. + */ +UTILS_PUBLIC +float illuminance(float aperture, float shutterSpeed, float sensitivity) noexcept; + +/** + * Converts the specified EV100 to illuminance in lux. + * EV100 is not a measure of illuminance, but an EV100 can be used to denote an + * illuminance for which a camera would use said EV100 to obtain the nominally + * correct exposure. + */ +UTILS_PUBLIC +float illuminance(float ev100) noexcept; + +} // namespace exposure +} // namespace filament + +#endif // TNT_FILAMENT_EXPOSURE_H diff --git a/package/ios/libs/filament/include/filament/Fence.h b/package/ios/libs/filament/include/filament/Fence.h new file mode 100644 index 00000000..673d12cd --- /dev/null +++ b/package/ios/libs/filament/include/filament/Fence.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_FENCE_H +#define TNT_FILAMENT_FENCE_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * Fence is used to synchronize the application main thread with filament's rendering thread. + */ +class UTILS_PUBLIC Fence : public FilamentAPI { +public: + //! Special \p timeout value to disable wait()'s timeout. + static constexpr uint64_t FENCE_WAIT_FOR_EVER = backend::FENCE_WAIT_FOR_EVER; + + //! Error codes for Fence::wait() + using FenceStatus = backend::FenceStatus; + + /** Mode controls the behavior of the command stream when calling wait() + * + * @attention + * It would be unwise to call `wait(..., Mode::DONT_FLUSH)` from the same thread + * the Fence was created, as it would most certainly create a dead-lock. + */ + enum class Mode : uint8_t { + FLUSH, //!< The command stream is flushed + DONT_FLUSH //!< The command stream is not flushed + }; + + /** + * Client-side wait on the Fence. + * + * Blocks the current thread until the Fence signals. + * + * @param mode Whether the command stream is flushed before waiting or not. + * @param timeout Wait time out. Using a \p timeout of 0 is a way to query the state of the fence. + * A \p timeout value of FENCE_WAIT_FOR_EVER is used to disable the timeout. + * @return FenceStatus::CONDITION_SATISFIED on success, + * FenceStatus::TIMEOUT_EXPIRED if the time out expired or + * FenceStatus::ERROR in other cases. + * @see #Mode + */ + FenceStatus wait(Mode mode = Mode::FLUSH, uint64_t timeout = FENCE_WAIT_FOR_EVER); + + /** + * Client-side wait on a Fence and destroy the Fence. + * + * @param fence Fence object to wait on. + * + * @param mode Whether the command stream is flushed before waiting or not. + * + * @return FenceStatus::CONDITION_SATISFIED on success, + * FenceStatus::ERROR otherwise. + */ + static FenceStatus waitAndDestroy(Fence* UTILS_NONNULL fence, Mode mode = Mode::FLUSH); + +protected: + // prevent heap allocation + ~Fence() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_FENCE_H diff --git a/package/ios/libs/filament/include/filament/FilamentAPI.h b/package/ios/libs/filament/include/filament/FilamentAPI.h new file mode 100644 index 00000000..19d6ba24 --- /dev/null +++ b/package/ios/libs/filament/include/filament/FilamentAPI.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_FILAMENTAPI_H +#define TNT_FILAMENT_FILAMENTAPI_H + +#include +#include + +#include + +namespace filament { + +/** + * \privatesection + * FilamentAPI is used to define an API in filament. + * It ensures the class defining the API can't be created, destroyed + * or copied by the caller. + */ +class UTILS_PUBLIC FilamentAPI { +protected: + // disallow creation on the stack + FilamentAPI() noexcept = default; + ~FilamentAPI() = default; + +public: + // disallow copy and assignment + FilamentAPI(FilamentAPI const&) = delete; + FilamentAPI(FilamentAPI&&) = delete; + FilamentAPI& operator=(FilamentAPI const&) = delete; + FilamentAPI& operator=(FilamentAPI&&) = delete; + + // allow placement-new allocation, don't use "noexcept", to avoid compiler null check + static void *operator new (size_t, void* p) { return p; } + + // prevent heap allocation + static void *operator new (size_t) = delete; + static void *operator new[] (size_t) = delete; +}; + +template +using BuilderBase = utils::PrivateImplementation; + +} // namespace filament + +#endif // TNT_FILAMENT_FILAMENTAPI_H diff --git a/package/ios/libs/filament/include/filament/Frustum.h b/package/ios/libs/filament/include/filament/Frustum.h new file mode 100644 index 00000000..ceec55eb --- /dev/null +++ b/package/ios/libs/filament/include/filament/Frustum.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_FRUSTUM_H +#define TNT_FILAMENT_FRUSTUM_H + +#include + +#include +#include +#include + +#include // Because we define NEAR and FAR in the Plane enum. + +#include + +namespace filament { + +class Box; +class Culler; + +/** + * A frustum defined by six planes + */ +class UTILS_PUBLIC Frustum { +public: + enum class Plane : uint8_t { + LEFT, + RIGHT, + BOTTOM, + TOP, + FAR, + NEAR + }; + + Frustum() = default; + Frustum(const Frustum& rhs) = default; + Frustum(Frustum&& rhs) noexcept = default; + Frustum& operator=(const Frustum& rhs) = default; + Frustum& operator=(Frustum&& rhs) noexcept = default; + + /** + * Creates a frustum from a projection matrix in GL convention + * (usually the projection * view matrix) + * @param pv a 4x4 projection matrix in GL convention + */ + explicit Frustum(const math::mat4f& pv); + + /** + * Sets the frustum from the given projection matrix + * @param pv a 4x4 projection matrix + */ + void setProjection(const math::mat4f& pv); + + /** + * Returns the plane equation parameters with normalized normals + * @param plane Identifier of the plane to retrieve the equation of + * @return A plane equation encoded a float4 R such as R.x*x + R.y*y + R.z*z + R.w = 0 + */ + math::float4 getNormalizedPlane(Plane plane) const noexcept; + + /** + * Returns a copy of all six frustum planes in left, right, bottom, top, far, near order + * @param planes six plane equations encoded as in getNormalizedPlane() in + * left, right, bottom, top, far, near order + */ + void getNormalizedPlanes(math::float4 planes[UTILS_NONNULL 6]) const noexcept; + + /** + * Returns all six frustum planes in left, right, bottom, top, far, near order + * @return six plane equations encoded as in getNormalizedPlane() in + * left, right, bottom, top, far, near order + */ + math::float4 const* UTILS_NONNULL getNormalizedPlanes() const noexcept { return mPlanes; } + + /** + * Returns whether a box intersects the frustum (i.e. is visible) + * @param box The box to test against the frustum + * @return true if the box may intersects the frustum, false otherwise. In some situations + * a box that doesn't intersect the frustum might be reported as though it does. However, + * a box that does intersect the frustum is always reported correctly (true). + */ + bool intersects(const Box& box) const noexcept; + + /** + * Returns whether a sphere intersects the frustum (i.e. is visible) + * @param sphere A sphere encoded as a center + radius. + * @return true if the sphere may intersects the frustum, false otherwise. In some situations + * a sphere that doesn't intersect the frustum might be reported as though it does. However, + * a sphere that does intersect the frustum is always reported correctly (true). + */ + bool intersects(const math::float4& sphere) const noexcept; + + /** + * Returns whether the frustum contains a given point. + * @param p the point to test + * @return the maximum signed distance to the frustum. Negative if p is inside. + */ + float contains(math::float3 p) const noexcept; + +private: + friend class Culler; + math::float4 mPlanes[6]; +}; + +} // namespace filament + +#if !defined(NDEBUG) +namespace utils::io { +class ostream; +} // namespace utils::io +utils::io::ostream& operator<<(utils::io::ostream& out, filament::Frustum const& frustum); +#endif + +#endif // TNT_FILAMENT_FRUSTUM_H diff --git a/package/ios/libs/filament/include/filament/IndexBuffer.h b/package/ios/libs/filament/include/filament/IndexBuffer.h new file mode 100644 index 00000000..35b8a10e --- /dev/null +++ b/package/ios/libs/filament/include/filament/IndexBuffer.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_INDEXBUFFER_H +#define TNT_FILAMENT_INDEXBUFFER_H + +#include + +#include + +#include + +#include + +#include +#include + +namespace filament { + +class FIndexBuffer; + +class Engine; + +/** + * A buffer containing vertex indices into a VertexBuffer. Indices can be 16 or 32 bit. + * The buffer itself is a GPU resource, therefore mutating the data can be relatively slow. + * Typically these buffers are constant. + * + * It is possible, and even encouraged, to use a single index buffer for several Renderables. + * + * @see VertexBuffer, RenderableManager + */ +class UTILS_PUBLIC IndexBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + using BufferDescriptor = backend::BufferDescriptor; + + /** + * Type of the index buffer + */ + enum class IndexType : uint8_t { + USHORT = uint8_t(backend::ElementType::USHORT), //!< 16-bit indices + UINT = uint8_t(backend::ElementType::UINT), //!< 32-bit indices + }; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the index buffer in elements. + * @param indexCount Number of indices the IndexBuffer can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& indexCount(uint32_t indexCount) noexcept; + + /** + * Type of the index buffer, 16-bit or 32-bit. + * @param indexType Type of indices stored in the IndexBuffer. + * @return A reference to this Builder for chaining calls. + */ + Builder& bufferType(IndexType indexType) noexcept; + + /** + * Creates the IndexBuffer object and returns a pointer to it. After creation, the index + * buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer. + * + * @param engine Reference to the filament::Engine to associate this IndexBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see IndexBuffer::setBuffer + */ + IndexBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FIndexBuffer; + }; + + /** + * Asynchronously copy-initializes a region of this IndexBuffer from the data provided. + * + * @param engine Reference to the filament::Engine to associate this IndexBuffer with. + * @param buffer A BufferDescriptor representing the data used to initialize the IndexBuffer. + * BufferDescriptor points to raw, untyped data that will be interpreted as + * either 16-bit or 32-bits indices based on the Type of this IndexBuffer. + * @param byteOffset Offset in *bytes* into the IndexBuffer + */ + void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0); + + /** + * Returns the size of this IndexBuffer in elements. + * @return The number of indices the IndexBuffer holds. + */ + size_t getIndexCount() const noexcept; + +protected: + // prevent heap allocation + ~IndexBuffer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_INDEXBUFFER_H diff --git a/package/ios/libs/filament/include/filament/IndirectLight.h b/package/ios/libs/filament/include/filament/IndirectLight.h new file mode 100644 index 00000000..c230dac8 --- /dev/null +++ b/package/ios/libs/filament/include/filament/IndirectLight.h @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_INDIRECTLIGHT_H +#define TNT_FILAMENT_INDIRECTLIGHT_H + +#include + +#include + +#include + +#include + +namespace filament { + +class Engine; +class Texture; + +class FIndirectLight; + +/** + * IndirectLight is used to simulate environment lighting, a form of global illumination. + * + * Environment lighting has a two components: + * 1. irradiance + * 2. reflections (specular component) + * + * Environments are usually captured as high-resolution HDR equirectangular images and processed + * by the **cmgen** tool to generate the data needed by IndirectLight. + * + * @note + * Currently IndirectLight is intended to be used for "distant probes", that is, to represent + * global illumination from a distant (i.e. at infinity) environment, such as the sky or distant + * mountains. Only a single IndirectLight can be used in a Scene. This limitation will be lifted + * in the future. + * + * Creation and destruction + * ======================== + * + * An IndirectLight object is created using the IndirectLight::Builder and destroyed by calling + * Engine::destroy(const IndirectLight*). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::IndirectLight* environment = filament::IndirectLight::Builder() + * .reflections(cubemap) + * .build(*engine); + * + * engine->destroy(environment); + * ~~~~~~~~~~~ + * + * + * Irradiance + * ========== + * + * The irradiance represents the light that comes from the environment and shines an + * object's surface. + * + * The irradiance is calculated automatically from the Reflections (see below), and generally + * doesn't need to be provided explicitly. However, it can be provided separately from the + * Reflections as + * [spherical harmonics](https://en.wikipedia.org/wiki/Spherical_harmonics) (SH) of 1, 2 or + * 3 bands, respectively 1, 4 or 9 coefficients. + * + * @note + * Use the **cmgen** tool to generate the `SH` for a given environment. + * + * Reflections + * =========== + * + * The reflections on object surfaces (specular component) is calculated from a specially + * filtered cubemap pyramid generated by the **cmgen** tool. + * + * + * @see Scene, Light, Texture, Skybox + */ +class UTILS_PUBLIC IndirectLight : public FilamentAPI { + struct BuilderDetails; + +public: + + //! Use Builder to construct an IndirectLight object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Set the reflections cubemap mipmap chain. + * + * @param cubemap A mip-mapped cubemap generated by **cmgen**. Each cubemap level + * encodes a the irradiance for a roughness level. + * + * @return This Builder, for chaining calls. + * + */ + Builder& reflections(Texture const* UTILS_NULLABLE cubemap) noexcept; + + /** + * Sets the irradiance as Spherical Harmonics. + * + * The irradiance must be pre-convolved by \f$ \langle n \cdot l \rangle \f$ and + * pre-multiplied by the Lambertian diffuse BRDF \f$ \frac{1}{\pi} \f$ and + * specified as Spherical Harmonics coefficients. + * + * Additionally, these Spherical Harmonics coefficients must be pre-scaled by the + * reconstruction factors \f$ A_{l}^{m} \f$ below. + * + * The final coefficients can be generated using the `cmgen` tool. + * + * The index in the \p sh array is given by: + * + * `index(l, m) = l * (l + 1) + m` + * + * \f$ sh[index(l,m)] = L_{l}^{m} \frac{1}{\pi} A_{l}^{m} \hat{C_{l}} \f$ + * + * index | l | m | \f$ A_{l}^{m} \f$ | \f$ \hat{C_{l}} \f$ | \f$ \frac{1}{\pi} A_{l}^{m}\hat{C_{l}} \f$ | + * :-----:|:---:|:---:|:------------------:|:---------------------:|:--------------------------------------------: + * 0 | 0 | 0 | 0.282095 | 3.1415926 | 0.282095 + * 1 | 1 | -1 | -0.488602 | 2.0943951 | -0.325735 + * 2 | ^ | 0 | 0.488602 | ^ | 0.325735 + * 3 | ^ | 1 | -0.488602 | ^ | -0.325735 + * 4 | 2 | -2 | 1.092548 | 0.785398 | 0.273137 + * 5 | ^ | -1 | -1.092548 | ^ | -0.273137 + * 6 | ^ | 0 | 0.315392 | ^ | 0.078848 + * 7 | ^ | 1 | -1.092548 | ^ | -0.273137 + * 8 | ^ | 2 | 0.546274 | ^ | 0.136569 + * + * + * Only 1, 2 or 3 bands are allowed. + * + * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. + * @param sh Array containing the spherical harmonics coefficients. + * The size of the array must be \f$ bands^{2} \f$. + * (i.e. 1, 4 or 9 coefficients respectively). + * + * @return This Builder, for chaining calls. + * + * @note + * Because the coefficients are pre-scaled, `sh[0]` is the environment's + * average irradiance. + */ + Builder& irradiance(uint8_t bands, math::float3 const* UTILS_NONNULL sh) noexcept; + + /** + * Sets the irradiance from the radiance expressed as Spherical Harmonics. + * + * The radiance must be specified as Spherical Harmonics coefficients \f$ L_{l}^{m} \f$ + * + * The index in the \p sh array is given by: + * + * `index(l, m) = l * (l + 1) + m` + * + * \f$ sh[index(l,m)] = L_{l}^{m} \f$ + * + * index | l | m + * :-----:|:---:|:---: + * 0 | 0 | 0 + * 1 | 1 | -1 + * 2 | ^ | 0 + * 3 | ^ | 1 + * 4 | 2 | -2 + * 5 | ^ | -1 + * 6 | ^ | 0 + * 7 | ^ | 1 + * 8 | ^ | 2 + * + * @param bands Number of spherical harmonics bands. Must be 1, 2 or 3. + * @param sh Array containing the spherical harmonics coefficients. + * The size of the array must be \f$ bands^{2} \f$. + * (i.e. 1, 4 or 9 coefficients respectively). + * + * @return This Builder, for chaining calls. + */ + Builder& radiance(uint8_t bands, math::float3 const* UTILS_NONNULL sh) noexcept; + + /** + * Sets the irradiance as a cubemap. + * + * The irradiance can alternatively be specified as a cubemap instead of Spherical + * Harmonics coefficients. It may or may not be more efficient, depending on your + * hardware (essentially, it's trading ALU for bandwidth). + * + * @param cubemap Cubemap representing the Irradiance pre-convolved by + * \f$ \langle n \cdot l \rangle \f$. + * + * @return This Builder, for chaining calls. + * + * @note + * This irradiance cubemap can be generated with the **cmgen** tool. + * + * @see irradiance(uint8_t bands, math::float3 const* sh) + */ + Builder& irradiance(Texture const* UTILS_NULLABLE cubemap) noexcept; + + /** + * (optional) Environment intensity. + * + * Because the environment is encoded usually relative to some reference, the + * range can be adjusted with this method. + * + * @param envIntensity Scale factor applied to the environment and irradiance such that + * the result is in lux, or lumen/m^2 (default = 30000) + * + * @return This Builder, for chaining calls. + */ + Builder& intensity(float envIntensity) noexcept; + + /** + * Specifies the rigid-body transformation to apply to the IBL. + * + * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. + * + * @return This Builder, for chaining calls. + */ + Builder& rotation(math::mat3f const& rotation) noexcept; + + /** + * Creates the IndirectLight object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this IndirectLight with. + * + * @return pointer to the newly created object or nullptr if exceptions are disabled and + * an error occurred. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + IndirectLight* UTILS_NONNULL build(Engine& engine); + + private: + friend class FIndirectLight; + }; + + /** + * Sets the environment's intensity. + * + * Because the environment is encoded usually relative to some reference, the + * range can be adjusted with this method. + * + * @param intensity Scale factor applied to the environment and irradiance such that + * the result is in lux, or lumen/m^2 (default = 30000) + */ + void setIntensity(float intensity) noexcept; + + /** + * Returns the environment's intensity in lux, or lumen/m^2. + */ + float getIntensity() const noexcept; + + /** + * Sets the rigid-body transformation to apply to the IBL. + * + * @param rotation 3x3 rotation matrix. Must be a rigid-body transform. + */ + void setRotation(math::mat3f const& rotation) noexcept; + + /** + * Returns the rigid-body transformation applied to the IBL. + */ + const math::mat3f& getRotation() const noexcept; + + /** + * Returns the associated reflection map, or null if it does not exist. + */ + Texture const* UTILS_NULLABLE getReflectionsTexture() const noexcept; + + /** + * Returns the associated irradiance map, or null if it does not exist. + */ + Texture const* UTILS_NULLABLE getIrradianceTexture() const noexcept; + + /** + * Helper to estimate the direction of the dominant light in the environment represented by + * spherical harmonics. + * + * This assumes that there is only a single dominant light (such as the sun in outdoors + * environments), if it's not the case the direction returned will be an average of the + * various lights based on their intensity. + * + * If there are no clear dominant light, as is often the case with low dynamic range (LDR) + * environments, this method may return a wrong or unexpected direction. + * + * The dominant light direction can be used to set a directional light's direction, + * for instance to produce shadows that match the environment. + * + * @param sh 3-band spherical harmonics + * + * @return A unit vector representing the direction of the dominant light + * + * @see LightManager::Builder::direction() + * @see getColorEstimate() + */ + static math::float3 getDirectionEstimate(const math::float3 sh[UTILS_NONNULL 9]) noexcept; + + /** + * Helper to estimate the color and relative intensity of the environment represented by + * spherical harmonics in a given direction. + * + * This can be used to set the color and intensity of a directional light. In this case + * make sure to multiply this relative intensity by the the intensity of this indirect light. + * + * @param sh 3-band spherical harmonics + * @param direction a unit vector representing the direction of the light to estimate the + * color of. Typically this the value returned by getDirectionEstimate(). + * + * @return A vector of 4 floats where the first 3 components represent the linear color and + * the 4th component represents the intensity of the dominant light + * + * @see LightManager::Builder::color() + * @see LightManager::Builder::intensity() + * @see getDirectionEstimate, getIntensity, setIntensity + */ + static math::float4 getColorEstimate(const math::float3 sh[UTILS_NONNULL 9], + math::float3 direction) noexcept; + + + /** @deprecated use static versions instead */ + UTILS_DEPRECATED + math::float3 getDirectionEstimate() const noexcept; + + /** @deprecated use static versions instead */ + UTILS_DEPRECATED + math::float4 getColorEstimate(math::float3 direction) const noexcept; + +protected: + // prevent heap allocation + ~IndirectLight() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_INDIRECTLIGHT_H diff --git a/package/ios/libs/filament/include/filament/InstanceBuffer.h b/package/ios/libs/filament/include/filament/InstanceBuffer.h new file mode 100644 index 00000000..2135152d --- /dev/null +++ b/package/ios/libs/filament/include/filament/InstanceBuffer.h @@ -0,0 +1,106 @@ +/* +* Copyright (C) 2023 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. +*/ + +#ifndef TNT_FILAMENT_INSTANCEBUFFER_H +#define TNT_FILAMENT_INSTANCEBUFFER_H + +#include +#include + +#include + +#include + +#include + +namespace filament { + +/** + * InstanceBuffer holds draw (GPU) instance transforms. These can be provided to a renderable to + * "offset" each draw instance. + * + * @see RenderableManager::Builder::instances(size_t, InstanceBuffer*) + */ +class UTILS_PUBLIC InstanceBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + + public: + + /** + * @param instanceCount the number of instances this InstanceBuffer will support, must be + * >= 1 and <= \c Engine::getMaxAutomaticInstances() + * @see Engine::getMaxAutomaticInstances + */ + explicit Builder(size_t instanceCount) noexcept; + + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Provide an initial local transform for each instance. Each local transform is relative to + * the transform of the associated renderable. This forms a parent-child relationship + * between the renderable and its instances, so adjusting the renderable's transform will +- * affect all instances. + * + * The array of math::mat4f must have length instanceCount, provided when constructing this + * Builder. + * + * @param localTransforms an array of math::mat4f with length instanceCount, must remain + * valid until after build() is called + */ + Builder& localTransforms(math::mat4f const* UTILS_NULLABLE localTransforms) noexcept; + + /** + * Creates the InstanceBuffer object and returns a pointer to it. + */ + InstanceBuffer* UTILS_NONNULL build(Engine& engine); + + private: + friend class FInstanceBuffer; + }; + + /** + * Returns the instance count specified when building this InstanceBuffer. + */ + size_t getInstanceCount() const noexcept; + + /** + * Sets the local transform for each instance. Each local transform is relative to the transform + * of the associated renderable. This forms a parent-child relationship between the renderable + * and its instances, so adjusting the renderable's transform will affect all instances. + * + * @param localTransforms an array of math::mat4f with length count, need not outlive this call + * @param count the number of local transforms + * @param offset index of the first instance to set local transforms + */ + void setLocalTransforms(math::mat4f const* UTILS_NONNULL localTransforms, + size_t count, size_t offset = 0); + +protected: + // prevent heap allocation + ~InstanceBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_INSTANCEBUFFER_H diff --git a/package/ios/libs/filament/include/filament/LightManager.h b/package/ios/libs/filament/include/filament/LightManager.h new file mode 100644 index 00000000..22d663f2 --- /dev/null +++ b/package/ios/libs/filament/include/filament/LightManager.h @@ -0,0 +1,977 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_LIGHTMANAGER_H +#define TNT_FILAMENT_LIGHTMANAGER_H + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class Engine; +class FEngine; +class FLightManager; + +/** + * LightManager allows to create a light source in the scene, such as a sun or street lights. + * + * At least one light must be added to a scene in order to see anything + * (unless the Material.Shading.UNLIT is used). + * + * + * Creation and destruction + * ======================== + * + * A Light component is created using the LightManager::Builder and destroyed by calling + * LightManager::destroy(utils::Entity). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * utils::Entity sun = utils::EntityManager.get().create(); + * + * filament::LightManager::Builder(Type::SUN) + * .castShadows(true) + * .build(*engine, sun); + * + * engine->getLightManager().destroy(sun); + * ~~~~~~~~~~~ + * + * + * Light types + * =========== + * + * Lights come in three flavors: + * - directional lights + * - point lights + * - spot lights + * + * + * Directional lights + * ------------------ + * + * Directional lights have a direction, but don't have a position. All light rays are + * parallel and come from infinitely far away and from everywhere. Typically a directional light + * is used to simulate the sun. + * + * Directional lights and spot lights are able to cast shadows. + * + * To create a directional light use Type.DIRECTIONAL or Type.SUN, both are similar, but the later + * also draws a sun's disk in the sky and its reflection on glossy objects. + * + * @warning Currently, only a single directional light is supported. If several directional lights + * are added to the scene, the dominant one will be used. + * + * @see Builder.direction(), Builder.sunAngularRadius() + * + * Point lights + * ------------ + * + * Unlike directional lights, point lights have a position but emit light in all directions. + * The intensity of the light diminishes with the inverse square of the distance to the light. + * Builder.falloff() controls distance beyond which the light has no more influence. + * + * A scene can have multiple point lights. + * + * @see Builder.position(), Builder.falloff() + * + * Spot lights + * ----------- + * + * Spot lights are similar to point lights but the light it emits is limited to a cone defined by + * Builder.spotLightCone() and the light's direction. + * + * A spot light is therefore defined by a position, a direction and inner and outer cones. The + * spot light's influence is limited to inside the outer cone. The inner cone defines the light's + * falloff attenuation. + * + * A physically correct spot light is a little difficult to use because changing the outer angle + * of the cone changes the illumination levels, as the same amount of light is spread over a + * changing volume. The coupling of illumination and the outer cone means that an artist cannot + * tweak the influence cone of a spot light without also changing the perceived illumination. + * It therefore makes sense to provide artists with a parameter to disable this coupling. This + * is the difference between Type.FOCUSED_SPOT and Type.SPOT. + * + * @see Builder.position(), Builder.direction(), Builder.falloff(), Builder.spotLightCone() + * + * Performance considerations + * ========================== + * + * Generally, adding lights to the scene hurts performance, however filament is designed to be + * able to handle hundreds of lights in a scene under certain conditions. Here are some tips + * to keep performances high. + * + * 1. Prefer spot lights to point lights and use the smallest outer cone angle possible. + * + * 2. Use the smallest possible falloff distance for point and spot lights. + * Performance is very sensitive to overlapping lights. The falloff distance essentially + * defines a sphere of influence for the light, so try to position point and spot lights + * such that they don't overlap too much. + * + * On the other hand, a scene can contain hundreds of non overlapping lights without + * incurring a significant overhead. + * + */ +class UTILS_PUBLIC LightManager : public FilamentAPI { + struct BuilderDetails; + +public: + using Instance = utils::EntityInstance; + + /** + * Returns the number of component in the LightManager, note that component are not + * guaranteed to be active. Use the EntityManager::isAlive() before use if needed. + * + * @return number of component in the LightManager + */ + size_t getComponentCount() const noexcept; + + /** + * Returns whether a particular Entity is associated with a component of this LightManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * Gets an Instance representing the Light component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the Light component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(utils::Entity e) const noexcept; + + // destroys this component from the given entity + void destroy(utils::Entity e) noexcept; + + + //! Denotes the type of the light being created. + enum class Type : uint8_t { + SUN, //!< Directional light that also draws a sun's disk in the sky. + DIRECTIONAL, //!< Directional light, emits light in a given direction. + POINT, //!< Point light, emits light from a position, in all directions. + FOCUSED_SPOT, //!< Physically correct spot light. + SPOT, //!< Spot light with coupling of outer cone and illumination disabled. + }; + + /** + * Control the quality / performance of the shadow map associated to this light + */ + struct ShadowOptions { + /** Size of the shadow map in texels. Must be a power-of-two and larger or equal to 8. */ + uint32_t mapSize = 1024; + + /** + * Number of shadow cascades to use for this light. Must be between 1 and 4 (inclusive). + * A value greater than 1 turns on cascaded shadow mapping (CSM). + * Only applicable to Type.SUN or Type.DIRECTIONAL lights. + * + * When using shadow cascades, cascadeSplitPositions must also be set. + * + * @see ShadowOptions::cascadeSplitPositions + */ + uint8_t shadowCascades = 1; + + /** + * The split positions for shadow cascades. + * + * Cascaded shadow mapping (CSM) partitions the camera frustum into cascades. These values + * determine the planes along the camera's Z axis to split the frustum. The camera near + * plane is represented by 0.0f and the far plane represented by 1.0f. + * + * For example, if using 4 cascades, these values would set a uniform split scheme: + * { 0.25f, 0.50f, 0.75f } + * + * For N cascades, N - 1 split positions will be read from this array. + * + * Filament provides utility methods inside LightManager::ShadowCascades to help set these + * values. For example, to use a uniform split scheme: + * + * ~~~~~~~~~~~{.cpp} + * LightManager::ShadowCascades::computeUniformSplits(options.splitPositions, 4); + * ~~~~~~~~~~~ + * + * @see ShadowCascades::computeUniformSplits + * @see ShadowCascades::computeLogSplits + * @see ShadowCascades::computePracticalSplits + */ + float cascadeSplitPositions[3] = { 0.125f, 0.25f, 0.50f }; + + /** Constant bias in world units (e.g. meters) by which shadows are moved away from the + * light. 1mm by default. + * This is ignored when the View's ShadowType is set to VSM. + */ + float constantBias = 0.001f; + + /** Amount by which the maximum sampling error is scaled. The resulting value is used + * to move the shadow away from the fragment normal. Should be 1.0. + * This is ignored when the View's ShadowType is set to VSM. + */ + float normalBias = 1.0f; + + /** Distance from the camera after which shadows are clipped. This is used to clip + * shadows that are too far and wouldn't contribute to the scene much, improving + * performance and quality. This value is always positive. + * Use 0.0f to use the camera far distance. + * This only affect directional lights. + */ + float shadowFar = 0.0f; + + /** Optimize the quality of shadows from this distance from the camera. Shadows will + * be rendered in front of this distance, but the quality may not be optimal. + * This value is always positive. Use 0.0f to use the camera near distance. + * The default of 1m works well with many scenes. The quality of shadows may drop + * rapidly when this value decreases. + */ + float shadowNearHint = 1.0f; + + /** Optimize the quality of shadows in front of this distance from the camera. Shadows + * will be rendered behind this distance, but the quality may not be optimal. + * This value is always positive. Use std::numerical_limits::infinity() to + * use the camera far distance. + */ + float shadowFarHint = 100.0f; + + /** + * Controls whether the shadow map should be optimized for resolution or stability. + * When set to true, all resolution enhancing features that can affect stability are + * disabling, resulting in significantly lower resolution shadows, albeit stable ones. + * + * Setting this flag to true always disables LiSPSM (see below). + * + * @see lispsm + */ + bool stable = false; + + /** + * LiSPSM, or light-space perspective shadow-mapping is a technique allowing to better + * optimize the use of the shadow-map texture. When enabled the effective resolution of + * shadows is greatly improved and yields result similar to using cascades without the + * extra cost. LiSPSM comes with some drawbacks however, in particular it is incompatible + * with blurring because it effectively affects the blur kernel size. + * + * Blurring is only an issue when using ShadowType::VSM with a large blur or with + * ShadowType::PCSS however. + * + * If these blurring artifacts become problematic, this flag can be used to disable LiSPSM. + * + * @see stable + */ + bool lispsm = true; + + /** + * Constant bias in depth-resolution units by which shadows are moved away from the + * light. The default value of 0.5 is used to round depth values up. + * Generally this value shouldn't be changed or at least be small and positive. + * This is ignored when the View's ShadowType is set to VSM. + */ + float polygonOffsetConstant = 0.5f; + + /** + * Bias based on the change in depth in depth-resolution units by which shadows are moved + * away from the light. The default value of 2.0 works well with SHADOW_SAMPLING_PCF_LOW. + * Generally this value is between 0.5 and the size in texel of the PCF filter. + * Setting this value correctly is essential for LISPSM shadow-maps. + * This is ignored when the View's ShadowType is set to VSM. + */ + float polygonOffsetSlope = 2.0f; + + /** + * Whether screen-space contact shadows are used. This applies regardless of whether a + * Renderable is a shadow caster. + * Screen-space contact shadows are typically useful in large scenes. + * (off by default) + */ + bool screenSpaceContactShadows = false; + + /** + * Number of ray-marching steps for screen-space contact shadows (8 by default). + * + * CAUTION: this parameter is ignored for all lights except the directional/sun light, + * all other lights use the same value set for the directional/sun light. + * + */ + uint8_t stepCount = 8; + + /** + * Maximum shadow-occluder distance for screen-space contact shadows (world units). + * (30 cm by default) + * + * CAUTION: this parameter is ignored for all lights except the directional/sun light, + * all other lights use the same value set for the directional/sun light. + * + */ + float maxShadowDistance = 0.3f; + + /** + * Options available when the View's ShadowType is set to VSM. + * + * @warning This API is still experimental and subject to change. + * @see View::setShadowType + */ + struct Vsm { + /** + * When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is + * an improvement to the default EVSM which suffers important light leaks. Enabling + * ELVSM for a single shadowmap doubles the memory usage of all shadow maps. + * ELVSM is mostly useful when large blurs are used. + */ + bool elvsm = false; + + /** + * Blur width for the VSM blur. Zero do disable. + * The maximum value is 125. + */ + float blurWidth = 0.0f; + } vsm; + + /** + * Light bulb radius used for soft shadows. Currently this is only used when DPCF or PCSS is + * enabled. (2cm by default). + */ + float shadowBulbRadius = 0.02f; + + /** + * Transforms the shadow direction. Must be a unit quaternion. + * The default is identity. + * Ignored if the light type isn't directional. For artistic use. Use with caution. + */ + math::quatf transform{ 1.0f }; + }; + + struct ShadowCascades { + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a uniform + * split scheme. + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + */ + static void computeUniformSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades); + + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a logarithmic + * split scheme. + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + * @param near the camera near plane + * @param far the camera far plane + */ + static void computeLogSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades, + float near, float far); + + /** + * Utility method to compute ShadowOptions::cascadeSplitPositions according to a practical + * split scheme. + * + * The practical split scheme uses uses a lambda value to interpolate between the logarithmic + * and uniform split schemes. Start with a lambda value of 0.5f and adjust for your scene. + * + * See: Zhang et al 2006, "Parallel-split shadow maps for large-scale virtual environments" + * + * @param splitPositions a float array of at least size (cascades - 1) to write the split + * positions into + * @param cascades the number of shadow cascades, at most 4 + * @param near the camera near plane + * @param far the camera far plane + * @param lambda a float in the range [0, 1] that interpolates between log and + * uniform split schemes + */ + static void computePracticalSplits(float* UTILS_NONNULL splitPositions, uint8_t cascades, + float near, float far, float lambda); + }; + + //! Use Builder to construct a Light object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + /** + * Creates a light builder and set the light's #Type. + * + * @param type #Type of Light object to create. + */ + explicit Builder(Type type) noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * + * @param channel Light channel to enable or disable, between 0 and 7. + * @param enable Whether to enable or disable the light channel. + * @return This Builder, for chaining calls. + */ + Builder& lightChannel(unsigned int channel, bool enable = true) noexcept; + + /** + * Whether this Light casts shadows (disabled by default) + * + * @param enable Enables or disables casting shadows from this Light. + * + * @return This Builder, for chaining calls. + */ + Builder& castShadows(bool enable) noexcept; + + /** + * Sets the shadow-map options for this light. + * + * @return This Builder, for chaining calls. + */ + Builder& shadowOptions(const ShadowOptions& options) noexcept; + + /** + * Whether this light casts light (enabled by default) + * + * @param enable Enables or disables lighting from this Light. + * + * @return This Builder, for chaining calls. + * + * @note + * In some situations it can be useful to have a light in the scene that doesn't + * actually emit light, but does cast shadows. + */ + Builder& castLight(bool enable) noexcept; + + /** + * Sets the initial position of the light in world space. + * + * @param position Light's position in world space. The default is at the origin. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's position is ignored for directional lights (Type.DIRECTIONAL or Type.SUN) + */ + Builder& position(const math::float3& position) noexcept; + + /** + * Sets the initial direction of a light in world space. + * + * @param direction Light's direction in world space. Should be a unit vector. + * The default is {0,-1,0}. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's direction is ignored for Type.POINT lights. + */ + Builder& direction(const math::float3& direction) noexcept; + + /** + * Sets the initial color of a light. + * + * @param color Color of the light specified in the linear sRGB color-space. + * The default is white {1,1,1}. + * + * @return This Builder, for chaining calls. + */ + Builder& color(const LinearColor& color) noexcept; + + /** + * Sets the initial intensity of a light. + * @param intensity This parameter depends on the Light.Type: + * - For directional lights, it specifies the illuminance in *lux* + * (or *lumen/m^2*). + * - For point lights and spot lights, it specifies the luminous power + * in *lumen*. + * + * @return This Builder, for chaining calls. + * + * For example, the sun's illuminance is about 100,000 lux. + * + * This method overrides any prior calls to intensity or intensityCandela. + * + */ + Builder& intensity(float intensity) noexcept; + + /** + * Sets the initial intensity of a spot or point light in candela. + * + * @param intensity Luminous intensity in *candela*. + * + * @return This Builder, for chaining calls. + * + * @note + * This method is equivalent to calling intensity(float intensity) for directional lights + * (Type.DIRECTIONAL or Type.SUN). + * + * This method overrides any prior calls to intensity or intensityCandela. + */ + Builder& intensityCandela(float intensity) noexcept; + + /** + * Sets the initial intensity of a light in watts. + * + * @param watts Energy consumed by a lightbulb. It is related to the energy produced + * and ultimately the brightness by the \p efficiency parameter. + * This value is often available on the packaging of commercial + * lightbulbs. + * + * @param efficiency Efficiency in percent. This depends on the type of lightbulb used. + * + * Lightbulb type | Efficiency + * ----------------:|-----------: + * Incandescent | 2.2% + * Halogen | 7.0% + * LED | 8.7% + * Fluorescent | 10.7% + * + * @return This Builder, for chaining calls. + * + * + * @note + * This call is equivalent to `Builder::intensity(efficiency * 683 * watts);` + * + * This method overrides any prior calls to intensity or intensityCandela. + */ + Builder& intensity(float watts, float efficiency) noexcept; + + /** + * Set the falloff distance for point lights and spot lights. + * + * At the falloff distance, the light has no more effect on objects. + * + * The falloff distance essentially defines a *sphere of influence* around the light, and + * therefore has an impact on performance. Larger falloffs might reduce performance + * significantly, especially when many lights are used. + * + * Try to avoid having a large number of light's spheres of influence overlap. + * + * @param radius Falloff distance in world units. Default is 1 meter. + * + * @return This Builder, for chaining calls. + * + * @note + * The Light's falloff is ignored for directional lights (Type.DIRECTIONAL or Type.SUN) + */ + Builder& falloff(float radius) noexcept; + + /** + * Defines a spot light'st angular falloff attenuation. + * + * A spot light is defined by a position, a direction and two cones, \p inner and \p outer. + * These two cones are used to define the angular falloff attenuation of the spot light + * and are defined by the angle from the center axis to where the falloff begins (i.e. + * cones are defined by their half-angle). + * + * Both inner and outer are silently clamped to a minimum value of 0.5 degrees + * (~0.00873 radians) to avoid floating-point precision issues during rendering. + * + * @param inner inner cone angle in *radians* between 0.00873 and \p outer + * @param outer outer cone angle in *radians* between 0.00873 inner and @f$ \pi/2 @f$ + * @return This Builder, for chaining calls. + * + * @note + * The spot light cone is ignored for directional and point lights. + * + * @see Type.SPOT, Type.FOCUSED_SPOT + */ + Builder& spotLightCone(float inner, float outer) noexcept; + + /** + * Defines the angular radius of the sun, in degrees, between 0.25° and 20.0° + * + * The Sun as seen from Earth has an angular size of 0.526° to 0.545° + * + * @param angularRadius sun's radius in degree. Default is 0.545°. + * + * @return This Builder, for chaining calls. + */ + Builder& sunAngularRadius(float angularRadius) noexcept; + + /** + * Defines the halo radius of the sun. The radius of the halo is defined as a + * multiplier of the sun angular radius. + * + * @param haloSize radius multiplier. Default is 10.0. + * + * @return This Builder, for chaining calls. + */ + Builder& sunHaloSize(float haloSize) noexcept; + + /** + * Defines the halo falloff of the sun. The falloff is a dimensionless number + * used as an exponent. + * + * @param haloFalloff halo falloff. Default is 80.0. + * + * @return This Builder, for chaining calls. + */ + Builder& sunHaloFalloff(float haloFalloff) noexcept; + + enum Result { Error = -1, Success = 0 }; + + /** + * Adds the Light component to an entity. + * + * @param engine Reference to the filament::Engine to associate this light with. + * @param entity Entity to add the light component to. + * @return Success if the component was created successfully, Error otherwise. + * + * If exceptions are disabled and an error occurs, this function is a no-op. + * Success can be checked by looking at the return value. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(utils::Entity e) was called. + * + * @warning + * Currently, only 2048 lights can be created on a given Engine. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Result build(Engine& engine, utils::Entity entity); + + private: + friend class FEngine; + friend class FLightManager; + }; + + static constexpr float EFFICIENCY_INCANDESCENT = 0.0220f; //!< Typical efficiency of an incandescent light bulb (2.2%) + static constexpr float EFFICIENCY_HALOGEN = 0.0707f; //!< Typical efficiency of an halogen light bulb (7.0%) + static constexpr float EFFICIENCY_FLUORESCENT = 0.0878f; //!< Typical efficiency of a fluorescent light bulb (8.7%) + static constexpr float EFFICIENCY_LED = 0.1171f; //!< Typical efficiency of a LED light bulb (11.7%) + + Type getType(Instance i) const noexcept; + + /** + * Helper function that returns if a light is a directional light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of directional light + */ + inline bool isDirectional(Instance i) const noexcept { + Type const type = getType(i); + return type == Type::DIRECTIONAL || type == Type::SUN; + } + + /** + * Helper function that returns if a light is a point light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of point light + */ + inline bool isPointLight(Instance i) const noexcept { + return getType(i) == Type::POINT; + } + + /** + * Helper function that returns if a light is a spot light + * + * @param i Instance of the component obtained from getInstance(). + * @return true is this light is a type of spot light + */ + inline bool isSpotLight(Instance i) const noexcept { + Type const type = getType(i); + return type == Type::SPOT || type == Type::FOCUSED_SPOT; + } + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * @param channel light channel to enable or disable, between 0 and 7. + * @param enable whether to enable (true) or disable (false) the specified light channel. + */ + void setLightChannel(Instance i, unsigned int channel, bool enable = true) noexcept; + + /** + * Returns whether a light channel is enabled on a specified light. + * @param i Instance of the component obtained from getInstance(). + * @param channel Light channel to query + * @return true if the light channel is enabled, false otherwise + */ + bool getLightChannel(Instance i, unsigned int channel) const noexcept; + + /** + * Dynamically updates the light's position. + * + * @param i Instance of the component obtained from getInstance(). + * @param position Light's position in world space. The default is at the origin. + * + * @see Builder.position() + */ + void setPosition(Instance i, const math::float3& position) noexcept; + + //! returns the light's position in world space + const math::float3& getPosition(Instance i) const noexcept; + + /** + * Dynamically updates the light's direction + * + * @param i Instance of the component obtained from getInstance(). + * @param direction Light's direction in world space. Should be a unit vector. + * The default is {0,-1,0}. + * + * @see Builder.direction() + */ + void setDirection(Instance i, const math::float3& direction) noexcept; + + //! returns the light's direction in world space + const math::float3& getDirection(Instance i) const noexcept; + + /** + * Dynamically updates the light's hue as linear sRGB + * + * @param i Instance of the component obtained from getInstance(). + * @param color Color of the light specified in the linear sRGB color-space. + * The default is white {1,1,1}. + * + * @see Builder.color(), getInstance() + */ + void setColor(Instance i, const LinearColor& color) noexcept; + + /** + * @param i Instance of the component obtained from getInstance(). + * @return the light's color in linear sRGB + */ + const math::float3& getColor(Instance i) const noexcept; + + /** + * Dynamically updates the light's intensity. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param intensity This parameter depends on the Light.Type: + * - For directional lights, it specifies the illuminance in *lux* + * (or *lumen/m^2*). + * - For point lights and spot lights, it specifies the luminous power + * in *lumen*. + * + * @see Builder.intensity() + */ + void setIntensity(Instance i, float intensity) noexcept; + + /** + * Dynamically updates the light's intensity. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param watts Energy consumed by a lightbulb. It is related to the energy produced + * and ultimately the brightness by the \p efficiency parameter. + * This value is often available on the packaging of commercial + * lightbulbs. + * @param efficiency Efficiency in percent. This depends on the type of lightbulb used. + * + * Lightbulb type | Efficiency + * ----------------:|-----------: + * Incandescent | 2.2% + * Halogen | 7.0% + * LED | 8.7% + * Fluorescent | 10.7% + * + * @see Builder.intensity(float watts, float efficiency) + */ + void setIntensity(Instance i, float watts, float efficiency) noexcept { + setIntensity(i, watts * 683.0f * efficiency); + } + + /** + * Dynamically updates the light's intensity in candela. The intensity can be negative. + * + * @param i Instance of the component obtained from getInstance(). + * @param intensity Luminous intensity in *candela*. + * + * @note + * This method is equivalent to calling setIntensity(float intensity) for directional lights + * (Type.DIRECTIONAL or Type.SUN). + * + * @see Builder.intensityCandela(float intensity) + */ + void setIntensityCandela(Instance i, float intensity) noexcept; + + /** + * returns the light's luminous intensity in candela. + * + * @param i Instance of the component obtained from getInstance(). + * + * @note for Type.FOCUSED_SPOT lights, the returned value depends on the \p outer cone angle. + * + * @return luminous intensity in candela. + */ + float getIntensity(Instance i) const noexcept; + + /** + * Set the falloff distance for point lights and spot lights. + * + * @param i Instance of the component obtained from getInstance(). + * @param radius falloff distance in world units. Default is 1 meter. + * + * @see Builder.falloff() + */ + void setFalloff(Instance i, float radius) noexcept; + + /** + * returns the falloff distance of this light. + * @param i Instance of the component obtained from getInstance(). + * @return the falloff distance of this light. + */ + float getFalloff(Instance i) const noexcept; + + /** + * Dynamically updates a spot light's cone as angles + * + * @param i Instance of the component obtained from getInstance(). + * @param inner inner cone angle in *radians* between 0.00873 and outer + * @param outer outer cone angle in *radians* between 0.00873 and pi/2 + * + * @see Builder.spotLightCone() + */ + void setSpotLightCone(Instance i, float inner, float outer) noexcept; + + /** + * returns the outer cone angle in *radians* between inner and pi/2. + * @param i Instance of the component obtained from getInstance(). + * @return the outer cone angle of this light. + */ + float getSpotLightOuterCone(Instance i) const noexcept; + + /** + * returns the inner cone angle in *radians* between 0 and pi/2. + * + * The value is recomputed from the initial values, thus is not precisely + * the same as the one passed to setSpotLightCone() or Builder.spotLightCone(). + * + * @param i Instance of the component obtained from getInstance(). + * @return the inner cone angle of this light. + */ + float getSpotLightInnerCone(Instance i) const noexcept; + + /** + * Dynamically updates the angular radius of a Type.SUN light + * + * The Sun as seen from Earth has an angular size of 0.526° to 0.545° + * + * @param i Instance of the component obtained from getInstance(). + * @param angularRadius sun's radius in degrees. Default is 0.545°. + */ + void setSunAngularRadius(Instance i, float angularRadius) noexcept; + + /** + * returns the angular radius if the sun in degrees. + * @param i Instance of the component obtained from getInstance(). + * @return the angular radius if the sun in degrees. + */ + float getSunAngularRadius(Instance i) const noexcept; + + /** + * Dynamically updates the halo radius of a Type.SUN light. The radius + * of the halo is defined as a multiplier of the sun angular radius. + * + * @param i Instance of the component obtained from getInstance(). + * @param haloSize radius multiplier. Default is 10.0. + */ + void setSunHaloSize(Instance i, float haloSize) noexcept; + + /** + * returns the halo size of a Type.SUN light as a multiplier of the + * sun angular radius. + * @param i Instance of the component obtained from getInstance(). + * @return the halo size + */ + float getSunHaloSize(Instance i) const noexcept; + + /** + * Dynamically updates the halo falloff of a Type.SUN light. The falloff + * is a dimensionless number used as an exponent. + * + * @param i Instance of the component obtained from getInstance(). + * @param haloFalloff halo falloff. Default is 80.0. + */ + void setSunHaloFalloff(Instance i, float haloFalloff) noexcept; + + /** + * returns the halo falloff of a Type.SUN light as a dimensionless value. + * @param i Instance of the component obtained from getInstance(). + * @return the halo falloff + */ + float getSunHaloFalloff(Instance i) const noexcept; + + /** + * returns the shadow-map options for a given light + * @param i Instance of the component obtained from getInstance(). + * @return A ShadowOption structure + */ + ShadowOptions const& getShadowOptions(Instance i) const noexcept; + + /** + * sets the shadow-map options for a given light + * @param i Instance of the component obtained from getInstance(). + * @param options A ShadowOption structure + */ + void setShadowOptions(Instance i, ShadowOptions const& options) noexcept; + + /** + * Whether this Light casts shadows (disabled by default) + * + * @param i Instance of the component obtained from getInstance(). + * @param shadowCaster Enables or disables casting shadows from this Light. + * + * @warning + * - Only a Type.DIRECTIONAL, Type.SUN, Type.SPOT, or Type.FOCUSED_SPOT light can cast shadows + */ + void setShadowCaster(Instance i, bool shadowCaster) noexcept; + + /** + * returns whether this light casts shadows. + * @param i Instance of the component obtained from getInstance(). + */ + bool isShadowCaster(Instance i) const noexcept; + +protected: + // prevent heap allocation + ~LightManager() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_LIGHTMANAGER_H diff --git a/package/ios/libs/filament/include/filament/Material.h b/package/ios/libs/filament/include/filament/Material.h new file mode 100644 index 00000000..b4b9bbed --- /dev/null +++ b/package/ios/libs/filament/include/filament/Material.h @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_MATERIAL_H +#define TNT_FILAMENT_MATERIAL_H + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +namespace utils { + class CString; +} // namespace utils + +namespace filament { + +class Texture; +class TextureSampler; + +class FEngine; +class FMaterial; + +class Engine; + +class UTILS_PUBLIC Material : public FilamentAPI { + struct BuilderDetails; + +public: + using BlendingMode = filament::BlendingMode; + using Shading = filament::Shading; + using Interpolation = filament::Interpolation; + using VertexDomain = filament::VertexDomain; + using TransparencyMode = filament::TransparencyMode; + + using ParameterType = backend::UniformType; + using Precision = backend::Precision; + using SamplerType = backend::SamplerType; + using SamplerFormat = backend::SamplerFormat; + using CullingMode = backend::CullingMode; + using ShaderModel = backend::ShaderModel; + using SubpassType = backend::SubpassType; + + /** + * Holds information about a material parameter. + */ + struct ParameterInfo { + //! Name of the parameter. + const char* UTILS_NONNULL name; + //! Whether the parameter is a sampler (texture). + bool isSampler; + //! Whether the parameter is a subpass type. + bool isSubpass; + union { + //! Type of the parameter if the parameter is not a sampler. + ParameterType type; + //! Type of the parameter if the parameter is a sampler. + SamplerType samplerType; + //! Type of the parameter if the parameter is a subpass. + SubpassType subpassType; + }; + //! Size of the parameter when the parameter is an array. + uint32_t count; + //! Requested precision of the parameter. + Precision precision; + }; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Specifies the material data. The material data is a binary blob produced by + * libfilamat or by matc. + * + * @param payload Pointer to the material data, must stay valid until build() is called. + * @param size Size of the material data pointed to by "payload" in bytes. + */ + Builder& package(const void* UTILS_NONNULL payload, size_t size); + + template + using is_supported_constant_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + + /** + * Specialize a constant parameter specified in the material definition with a concrete + * value for this material. Once build() is called, this constant cannot be changed. + * Will throw an exception if the name does not match a constant specified in the + * material definition or if the type provided does not match. + * + * @tparam T The type of constant parameter, either int32_t, float, or bool. + * @param name The name of the constant parameter specified in the material definition, such + * as "myConstant". + * @param nameLength Length in `char` of the name parameter. + * @param value The value to use for the constant parameter, must match the type specified + * in the material definition. + */ + template> + Builder& constant(const char* UTILS_NONNULL name, size_t nameLength, T value); + + /** inline helper to provide the constant name as a null-terminated C string */ + template> + inline Builder& constant(const char* UTILS_NONNULL name, T value) { + return constant(name, strlen(name), value); + } + + /** + * Creates the Material object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Material with. + * + * @return pointer to the newly created object or nullptr if exceptions are disabled and + * an error occurred. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Material* UTILS_NULLABLE build(Engine& engine); + private: + friend class FMaterial; + }; + + using CompilerPriorityQueue = backend:: CompilerPriorityQueue; + + /** + * Asynchronously ensures that a subset of this Material's variants are compiled. After issuing + * several Material::compile() calls in a row, it is recommended to call Engine::flush() + * such that the backend can start the compilation work as soon as possible. + * The provided callback is guaranteed to be called on the main thread after all specified + * variants of the material are compiled. This can take hundreds of milliseconds. + * + * If all the material's variants are already compiled, the callback will be scheduled as + * soon as possible, but this might take a few dozen millisecond, corresponding to how + * many previous frames are enqueued in the backend. This also varies by backend. Therefore, + * it is recommended to only call this method once per material shortly after creation. + * + * If the same variant is scheduled for compilation multiple times, the first scheduling + * takes precedence; later scheduling are ignored. + * + * caveat: A consequence is that if a variant is scheduled on the low priority queue and later + * scheduled again on the high priority queue, the later scheduling is ignored. + * Therefore, the second callback could be called before the variant is compiled. + * However, the first callback, if specified, will trigger as expected. + * + * The callback is guaranteed to be called. If the engine is destroyed while some material + * variants are still compiling or in the queue, these will be discarded and the corresponding + * callback will be called. In that case however the Material pointer passed to the callback + * is guaranteed to be invalid (either because it's been destroyed by the user already, or, + * because it's been cleaned-up by the Engine). + * + * UserVariantFilterMask::ALL should be used with caution. Only variants that an application + * needs should be included in the variants argument. For example, the STE variant is only used + * for stereoscopic rendering. If an application is not planning to render in stereo, this bit + * should be turned off to avoid unnecessary material compilations. + * + * @param priority Which priority queue to use, LOW or HIGH. + * @param variants Variants to include to the compile command. + * @param handler Handler to dispatch the callback or nullptr for the default handler + * @param callback callback called on the main thread when the compilation is done on + * by backend. + */ + void compile(CompilerPriorityQueue priority, + UserVariantFilterMask variants, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept; + + inline void compile(CompilerPriorityQueue priority, + UserVariantFilterBit variants, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept { + compile(priority, UserVariantFilterMask(variants), handler, + std::forward>(callback)); + } + + inline void compile(CompilerPriorityQueue priority, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + utils::Invocable&& callback = {}) noexcept { + compile(priority, UserVariantFilterBit::ALL, handler, + std::forward>(callback)); + } + + /** + * Creates a new instance of this material. Material instances should be freed using + * Engine::destroy(const MaterialInstance*). + * + * @param name Optional name to associate with the given material instance. If this is null, + * then the instance inherits the material's name. + * + * @return A pointer to the new instance. + */ + MaterialInstance* UTILS_NONNULL createInstance(const char* UTILS_NULLABLE name = nullptr) const noexcept; + + //! Returns the name of this material as a null-terminated string. + const char* UTILS_NONNULL getName() const noexcept; + + //! Returns the shading model of this material. + Shading getShading() const noexcept; + + //! Returns the interpolation mode of this material. This affects how variables are interpolated. + Interpolation getInterpolation() const noexcept; + + //! Returns the blending mode of this material. + BlendingMode getBlendingMode() const noexcept; + + //! Returns the vertex domain of this material. + VertexDomain getVertexDomain() const noexcept; + + //! Returns the material's supported variants + UserVariantFilterMask getSupportedVariants() const noexcept; + + //! Returns the material domain of this material. + //! The material domain determines how the material is used. + MaterialDomain getMaterialDomain() const noexcept; + + //! Returns the default culling mode of this material. + CullingMode getCullingMode() const noexcept; + + //! Returns the transparency mode of this material. + //! This value only makes sense when the blending mode is transparent or fade. + TransparencyMode getTransparencyMode() const noexcept; + + //! Indicates whether instances of this material will, by default, write to the color buffer. + bool isColorWriteEnabled() const noexcept; + + //! Indicates whether instances of this material will, by default, write to the depth buffer. + bool isDepthWriteEnabled() const noexcept; + + //! Indicates whether instances of this material will, by default, use depth testing. + bool isDepthCullingEnabled() const noexcept; + + //! Indicates whether this material is double-sided. + bool isDoubleSided() const noexcept; + + //! Indicates whether this material uses alpha to coverage. + bool isAlphaToCoverageEnabled() const noexcept; + + //! Returns the alpha mask threshold used when the blending mode is set to masked. + float getMaskThreshold() const noexcept; + + //! Indicates whether this material uses the shadowing factor as a color multiplier. + //! This values only makes sense when the shading mode is unlit. + bool hasShadowMultiplier() const noexcept; + + //! Indicates whether this material has specular anti-aliasing enabled + bool hasSpecularAntiAliasing() const noexcept; + + //! Returns the screen-space variance for specular-antialiasing, this value is between 0 and 1. + float getSpecularAntiAliasingVariance() const noexcept; + + //! Returns the clamping threshold for specular-antialiasing, this value is between 0 and 1. + float getSpecularAntiAliasingThreshold() const noexcept; + + //! Returns the list of vertex attributes required by this material. + AttributeBitset getRequiredAttributes() const noexcept; + + //! Returns the refraction mode used by this material. + RefractionMode getRefractionMode() const noexcept; + + //! Return the refraction type used by this material. + RefractionType getRefractionType() const noexcept; + + //! Returns the reflection mode used by this material. + ReflectionMode getReflectionMode() const noexcept; + + //! Returns the minimum required feature level for this material. + backend::FeatureLevel getFeatureLevel() const noexcept; + + /** + * Returns the number of parameters declared by this material. + * The returned value can be 0. + */ + size_t getParameterCount() const noexcept; + + /** + * Gets information about this material's parameters. + * + * @param parameters A pointer to a list of ParameterInfo. + * The list must be at least "count" large + * @param count The number of parameters to retrieve. Must be >= 0 and can be > count. + * + * @return The number of parameters written to the parameters pointer. + */ + size_t getParameters(ParameterInfo* UTILS_NONNULL parameters, size_t count) const noexcept; + + //! Indicates whether a parameter of the given name exists on this material. + bool hasParameter(const char* UTILS_NONNULL name) const noexcept; + + //! Indicates whether an existing parameter is a sampler or not. + bool isSampler(const char* UTILS_NONNULL name) const noexcept; + + /** + * Sets the value of the given parameter on this material's default instance. + * + * @param name The name of the material parameter + * @param value The value of the material parameter + * + * @see getDefaultInstance() + */ + template + void setDefaultParameter(const char* UTILS_NONNULL name, T value) noexcept { + getDefaultInstance()->setParameter(name, value); + } + + /** + * Sets a texture and sampler parameters on this material's default instance. + * + * @param name The name of the material texture parameter + * @param texture The texture to set as parameter + * @param sampler The sampler to be used with this texture + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) noexcept { + getDefaultInstance()->setParameter(name, texture, sampler); + } + + /** + * Sets the color of the given parameter on this material's default instance. + * + * @param name The name of the material color parameter + * @param type Whether the color is specified in the linear or sRGB space + * @param color The color as a floating point red, green, blue tuple + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) noexcept { + getDefaultInstance()->setParameter(name, type, color); + } + + /** + * Sets the color of the given parameter on this material's default instance. + * + * @param name The name of the material color parameter + * @param type Whether the color is specified in the linear or sRGB space + * @param color The color as a floating point red, green, blue, alpha tuple + * + * @see getDefaultInstance() + */ + void setDefaultParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) noexcept { + getDefaultInstance()->setParameter(name, type, color); + } + + //! Returns this material's default instance. + MaterialInstance* UTILS_NONNULL getDefaultInstance() noexcept; + + //! Returns this material's default instance. + MaterialInstance const* UTILS_NONNULL getDefaultInstance() const noexcept; + +protected: + // prevent heap allocation + ~Material() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_MATERIAL_H diff --git a/package/ios/libs/filament/include/filament/MaterialChunkType.h b/package/ios/libs/filament/include/filament/MaterialChunkType.h new file mode 100644 index 00000000..6cff2003 --- /dev/null +++ b/package/ios/libs/filament/include/filament/MaterialChunkType.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H +#define TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H + +#include + +#include + +namespace filamat { + +// Pack an eight character string into a 64 bit integer. +constexpr inline uint64_t charTo64bitNum(const char str[9]) noexcept { + return + ( (static_cast(str[0]) << 56)) + | ((static_cast(str[1]) << 48) & 0x00FF000000000000U) + | ((static_cast(str[2]) << 40) & 0x0000FF0000000000U) + | ((static_cast(str[3]) << 32) & 0x000000FF00000000U) + | ((static_cast(str[4]) << 24) & 0x00000000FF000000U) + | ((static_cast(str[5]) << 16) & 0x0000000000FF0000U) + | ((static_cast(str[6]) << 8) & 0x000000000000FF00U) + | ( static_cast(str[7]) & 0x00000000000000FFU); +} + +enum UTILS_PUBLIC ChunkType : uint64_t { + Unknown = charTo64bitNum("UNKNOWN "), + MaterialUib = charTo64bitNum("MAT_UIB "), + MaterialSib = charTo64bitNum("MAT_SIB "), + MaterialSubpass = charTo64bitNum("MAT_SUB "), + MaterialGlsl = charTo64bitNum("MAT_GLSL"), + MaterialEssl1 = charTo64bitNum("MAT_ESS1"), + MaterialSpirv = charTo64bitNum("MAT_SPIR"), + MaterialMetal = charTo64bitNum("MAT_METL"), + MaterialShaderModels = charTo64bitNum("MAT_SMDL"), + MaterialSamplerBindings = charTo64bitNum("MAT_SAMP"), + MaterialUniformBindings = charTo64bitNum("MAT_UNIF"), + MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"), + MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"), + MaterialProperties = charTo64bitNum("MAT_PROP"), + MaterialConstants = charTo64bitNum("MAT_CONS"), + + MaterialName = charTo64bitNum("MAT_NAME"), + MaterialVersion = charTo64bitNum("MAT_VERS"), + MaterialCacheId = charTo64bitNum("MAT_UUID"), + MaterialFeatureLevel = charTo64bitNum("MAT_FEAT"), + MaterialShading = charTo64bitNum("MAT_SHAD"), + MaterialBlendingMode = charTo64bitNum("MAT_BLEN"), + MaterialTransparencyMode = charTo64bitNum("MAT_TRMD"), + MaterialMaskThreshold = charTo64bitNum("MAT_THRS"), + MaterialShadowMultiplier = charTo64bitNum("MAT_SHML"), + MaterialSpecularAntiAliasing = charTo64bitNum("MAT_SPAA"), + MaterialSpecularAntiAliasingVariance = charTo64bitNum("MAT_SVAR"), + MaterialSpecularAntiAliasingThreshold = charTo64bitNum("MAT_STHR"), + MaterialClearCoatIorChange = charTo64bitNum("MAT_CIOR"), + MaterialDomain = charTo64bitNum("MAT_DOMN"), + MaterialVariantFilterMask = charTo64bitNum("MAT_VFLT"), + MaterialRefraction = charTo64bitNum("MAT_REFM"), + MaterialRefractionType = charTo64bitNum("MAT_REFT"), + MaterialReflectionMode = charTo64bitNum("MAT_REFL"), + + MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"), + MaterialDoubleSidedSet = charTo64bitNum("MAT_DOSS"), + MaterialDoubleSided = charTo64bitNum("MAT_DOSI"), + + MaterialColorWrite = charTo64bitNum("MAT_CWRIT"), + MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"), + MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"), + MaterialDepthTest = charTo64bitNum("MAT_DTEST"), + MaterialInstanced = charTo64bitNum("MAT_INSTA"), + MaterialCullingMode = charTo64bitNum("MAT_CUMO"), + MaterialAlphaToCoverageSet = charTo64bitNum("MAT_A2CS"), + MaterialAlphaToCoverage = charTo64bitNum("MAT_A2CO"), + + MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"), + + MaterialVertexDomain = charTo64bitNum("MAT_VEDO"), + MaterialInterpolation = charTo64bitNum("MAT_INTR"), + + DictionaryText = charTo64bitNum("DIC_TEXT"), + DictionarySpirv = charTo64bitNum("DIC_SPIR"), +}; + +} // namespace filamat + +#endif // TNT_FILAMAT_MATERIAL_CHUNK_TYPES_H diff --git a/package/ios/libs/filament/include/filament/MaterialEnums.h b/package/ios/libs/filament/include/filament/MaterialEnums.h new file mode 100644 index 00000000..f98c707e --- /dev/null +++ b/package/ios/libs/filament/include/filament/MaterialEnums.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_MATERIAL_ENUM_H +#define TNT_FILAMENT_MATERIAL_ENUM_H + +#include +#include + +#include +#include + +namespace filament { + +// update this when a new version of filament wouldn't work with older materials +static constexpr size_t MATERIAL_VERSION = 50; + +/** + * Supported shading models + */ +enum class Shading : uint8_t { + UNLIT, //!< no lighting applied, emissive possible + LIT, //!< default, standard lighting + SUBSURFACE, //!< subsurface lighting model + CLOTH, //!< cloth lighting model + SPECULAR_GLOSSINESS, //!< legacy lighting model +}; + +/** + * Attribute interpolation types in the fragment shader + */ +enum class Interpolation : uint8_t { + SMOOTH, //!< default, smooth interpolation + FLAT //!< flat interpolation +}; + +/** + * Shader quality, affect some global quality parameters + */ +enum class ShaderQuality : int8_t { + DEFAULT = -1, // LOW on mobile, HIGH on desktop + LOW = 0, // enable optimizations that can slightly affect correctness + NORMAL = 1, // normal quality, correctness honored + HIGH = 2 // higher quality (e.g. better upscaling, etc...) +}; + +/** + * Supported blending modes + */ +enum class BlendingMode : uint8_t { + //! material is opaque + OPAQUE, + //! material is transparent and color is alpha-pre-multiplied, affects diffuse lighting only + TRANSPARENT, + //! material is additive (e.g.: hologram) + ADD, + //! material is masked (i.e. alpha tested) + MASKED, + /** + * material is transparent and color is alpha-pre-multiplied, affects specular lighting + * when adding more entries, change the size of FRenderer::CommandKey::blending + */ + FADE, + //! material darkens what's behind it + MULTIPLY, + //! material brightens what's behind it + SCREEN, +}; + +/** + * How transparent objects are handled + */ +enum class TransparencyMode : uint8_t { + //! the transparent object is drawn honoring the raster state + DEFAULT, + /** + * the transparent object is first drawn in the depth buffer, + * then in the color buffer, honoring the culling mode, but ignoring the depth test function + */ + TWO_PASSES_ONE_SIDE, + + /** + * the transparent object is drawn twice in the color buffer, + * first with back faces only, then with front faces; the culling + * mode is ignored. Can be combined with two-sided lighting + */ + TWO_PASSES_TWO_SIDES +}; + +/** + * Supported types of vertex domains. + */ +enum class VertexDomain : uint8_t { + OBJECT, //!< vertices are in object space, default + WORLD, //!< vertices are in world space + VIEW, //!< vertices are in view space + DEVICE //!< vertices are in normalized device space + // when adding more entries, make sure to update VERTEX_DOMAIN_COUNT +}; + +/** + * Vertex attribute types + */ +enum VertexAttribute : uint8_t { + // Update hasIntegerTarget() in VertexBuffer when adding an attribute that will + // be read as integers in the shaders + + POSITION = 0, //!< XYZ position (float3) + TANGENTS = 1, //!< tangent, bitangent and normal, encoded as a quaternion (float4) + COLOR = 2, //!< vertex color (float4) + UV0 = 3, //!< texture coordinates (float2) + UV1 = 4, //!< texture coordinates (float2) + BONE_INDICES = 5, //!< indices of 4 bones, as unsigned integers (uvec4) + BONE_WEIGHTS = 6, //!< weights of the 4 bones (normalized float4) + // -- we have 1 unused slot here -- + CUSTOM0 = 8, + CUSTOM1 = 9, + CUSTOM2 = 10, + CUSTOM3 = 11, + CUSTOM4 = 12, + CUSTOM5 = 13, + CUSTOM6 = 14, + CUSTOM7 = 15, + + // Aliases for legacy vertex morphing. + // See RenderableManager::Builder::morphing(). + MORPH_POSITION_0 = CUSTOM0, + MORPH_POSITION_1 = CUSTOM1, + MORPH_POSITION_2 = CUSTOM2, + MORPH_POSITION_3 = CUSTOM3, + MORPH_TANGENTS_0 = CUSTOM4, + MORPH_TANGENTS_1 = CUSTOM5, + MORPH_TANGENTS_2 = CUSTOM6, + MORPH_TANGENTS_3 = CUSTOM7, + + // this is limited by driver::MAX_VERTEX_ATTRIBUTE_COUNT +}; + +static constexpr size_t MAX_LEGACY_MORPH_TARGETS = 4; +static constexpr size_t MAX_MORPH_TARGETS = 256; // this is limited by filament::CONFIG_MAX_MORPH_TARGET_COUNT +static constexpr size_t MAX_CUSTOM_ATTRIBUTES = 8; + +/** + * Material domains + */ +enum class MaterialDomain : uint8_t { + SURFACE = 0, //!< shaders applied to renderables + POST_PROCESS = 1, //!< shaders applied to rendered buffers + COMPUTE = 2, //!< compute shader +}; + +/** + * Specular occlusion + */ +enum class SpecularAmbientOcclusion : uint8_t { + NONE = 0, //!< no specular occlusion + SIMPLE = 1, //!< simple specular occlusion + BENT_NORMALS = 2, //!< more accurate specular occlusion, requires bent normals +}; + +/** + * Refraction + */ +enum class RefractionMode : uint8_t { + NONE = 0, //!< no refraction + CUBEMAP = 1, //!< refracted rays go to the ibl cubemap + SCREEN_SPACE = 2, //!< refracted rays go to screen space +}; + +/** + * Refraction type + */ +enum class RefractionType : uint8_t { + SOLID = 0, //!< refraction through solid objects (e.g. a sphere) + THIN = 1, //!< refraction through thin objects (e.g. window) +}; + +/** + * Reflection mode + */ +enum class ReflectionMode : uint8_t { + DEFAULT = 0, //! reflections sample from the scene's IBL only + SCREEN_SPACE = 1, //! reflections sample from screen space, and fallback to the scene's IBL +}; + +// can't really use std::underlying_type::type because the driver takes a uint32_t +using AttributeBitset = utils::bitset32; + +static constexpr size_t MATERIAL_PROPERTIES_COUNT = 26; +enum class Property : uint8_t { + BASE_COLOR, //!< float4, all shading models + ROUGHNESS, //!< float, lit shading models only + METALLIC, //!< float, all shading models, except unlit and cloth + REFLECTANCE, //!< float, all shading models, except unlit and cloth + AMBIENT_OCCLUSION, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT_ROUGHNESS, //!< float, lit shading models only, except subsurface and cloth + CLEAR_COAT_NORMAL, //!< float, lit shading models only, except subsurface and cloth + ANISOTROPY, //!< float, lit shading models only, except subsurface and cloth + ANISOTROPY_DIRECTION, //!< float3, lit shading models only, except subsurface and cloth + THICKNESS, //!< float, subsurface shading model only + SUBSURFACE_POWER, //!< float, subsurface shading model only + SUBSURFACE_COLOR, //!< float3, subsurface and cloth shading models only + SHEEN_COLOR, //!< float3, lit shading models only, except subsurface + SHEEN_ROUGHNESS, //!< float3, lit shading models only, except subsurface and cloth + SPECULAR_COLOR, //!< float3, specular-glossiness shading model only + GLOSSINESS, //!< float, specular-glossiness shading model only + EMISSIVE, //!< float4, all shading models + NORMAL, //!< float3, all shading models only, except unlit + POST_LIGHTING_COLOR, //!< float4, all shading models + CLIP_SPACE_TRANSFORM, //!< mat4, vertex shader only + ABSORPTION, //!< float3, how much light is absorbed by the material + TRANSMISSION, //!< float, how much light is refracted through the material + IOR, //!< float, material's index of refraction + MICRO_THICKNESS, //!< float, thickness of the thin layer + BENT_NORMAL, //!< float3, all shading models only, except unlit + + // when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT +}; + +using UserVariantFilterMask = uint32_t; + +enum class UserVariantFilterBit : UserVariantFilterMask { + DIRECTIONAL_LIGHTING = 0x01, //!< Directional lighting + DYNAMIC_LIGHTING = 0x02, //!< Dynamic lighting + SHADOW_RECEIVER = 0x04, //!< Shadow receiver + SKINNING = 0x08, //!< Skinning + FOG = 0x10, //!< Fog + VSM = 0x20, //!< Variance shadow maps + SSR = 0x40, //!< Screen-space reflections + STE = 0x80, //!< Instanced stereo rendering + ALL = 0xFF, +}; + +} // namespace filament + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif diff --git a/package/ios/libs/filament/include/filament/MaterialInstance.h b/package/ios/libs/filament/include/filament/MaterialInstance.h new file mode 100644 index 00000000..a0edd135 --- /dev/null +++ b/package/ios/libs/filament/include/filament/MaterialInstance.h @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_FILAMENT_MATERIALINSTANCE_H +#define TNT_FILAMENT_MATERIALINSTANCE_H + +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +namespace filament { + +class Material; +class Texture; +class TextureSampler; +class UniformBuffer; +class BufferInterfaceBlock; + +class UTILS_PUBLIC MaterialInstance : public FilamentAPI { + template + using StringLiteralHelper = const char[N]; + + struct StringLiteral { + const char* UTILS_NONNULL data; + size_t size; + template + StringLiteral(StringLiteralHelper const& s) noexcept // NOLINT(google-explicit-constructor) + : data(s), size(N - 1) { + } + }; + +public: + using CullingMode = filament::backend::CullingMode; + using TransparencyMode = filament::TransparencyMode; + using DepthFunc = filament::backend::SamplerCompareFunc; + using StencilCompareFunc = filament::backend::SamplerCompareFunc; + using StencilOperation = filament::backend::StencilOperation; + using StencilFace = filament::backend::StencilFace; + + template + using is_supported_parameter_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + // these types are slower as they need a layout conversion + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type; + + /** + * Creates a new MaterialInstance using another MaterialInstance as a template for initialization. + * The new MaterialInstance is an instance of the same Material of the template instance and + * must be destroyed just like any other MaterialInstance. + * + * @param other A MaterialInstance to use as a template for initializing a new instance + * @param name A name for the new MaterialInstance or nullptr to use the template's name + * @return A new MaterialInstance + */ + static MaterialInstance* UTILS_NONNULL duplicate(MaterialInstance const* UTILS_NONNULL other, + const char* UTILS_NULLABLE name = nullptr) noexcept; + + /** + * @return the Material associated with this instance + */ + Material const* UTILS_NONNULL getMaterial() const noexcept; + + /** + * @return the name associated with this instance + */ + const char* UTILS_NONNULL getName() const noexcept; + + /** + * Set a uniform by name + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param value Value of the parameter to set. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + template> + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, T const& value); + + /** inline helper to provide the name as a null-terminated string literal */ + template> + inline void setParameter(StringLiteral name, T const& value) { + setParameter(name.data, name.size, value); + } + + /** inline helper to provide the name as a null-terminated C string */ + template> + inline void setParameter(const char* UTILS_NONNULL name, T const& value) { + setParameter(name, strlen(name), value); + } + + + /** + * Set a uniform array by name + * + * @param name Name of the parameter array as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param values Array of values to set to the named parameter array. + * @param count Size of the array to set. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + template> + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + const T* UTILS_NONNULL values, size_t count); + + /** inline helper to provide the name as a null-terminated string literal */ + template> + inline void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t count) { + setParameter(name.data, name.size, values, count); + } + + /** inline helper to provide the name as a null-terminated C string */ + template> + inline void setParameter(const char* UTILS_NONNULL name, + const T* UTILS_NONNULL values, size_t count) { + setParameter(name, strlen(name), values, count); + } + + + /** + * Set a texture as the named parameter + * + * Note: Depth textures can't be sampled with a linear filter unless the comparison mode is set + * to COMPARE_TO_TEXTURE. + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param texture Non nullptr Texture object pointer. + * @param sampler Sampler parameters. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) { + setParameter(name.data, name.size, texture, sampler); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, + Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) { + setParameter(name, strlen(name), texture, sampler); + } + + + /** + * Set an RGB color as the named parameter. + * A conversion might occur depending on the specified type + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param type Whether the color value is encoded as Linear or sRGB. + * @param color Array of read, green, blue channels values. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + RgbType type, math::float3 color); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, RgbType type, math::float3 color) { + setParameter(name.data, name.size, type, color); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) { + setParameter(name, strlen(name), type, color); + } + + + /** + * Set an RGBA color as the named parameter. + * A conversion might occur depending on the specified type + * + * @param name Name of the parameter as defined by Material. Cannot be nullptr. + * @param nameLength Length in `char` of the name parameter. + * @param type Whether the color value is encoded as Linear or sRGB/A. + * @param color Array of read, green, blue and alpha channels values. + * @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled. + */ + void setParameter(const char* UTILS_NONNULL name, size_t nameLength, + RgbaType type, math::float4 color); + + /** inline helper to provide the name as a null-terminated string literal */ + inline void setParameter(StringLiteral name, RgbaType type, math::float4 color) { + setParameter(name.data, name.size, type, color); + } + + /** inline helper to provide the name as a null-terminated C string */ + inline void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) { + setParameter(name, strlen(name), type, color); + } + + /** + * Set-up a custom scissor rectangle; by default it is disabled. + * + * The scissor rectangle gets clipped by the View's viewport, in other words, the scissor + * cannot affect fragments outside of the View's Viewport. + * + * Currently the scissor is not compatible with dynamic resolution and should always be + * disabled when dynamic resolution is used. + * + * @param left left coordinate of the scissor box relative to the viewport + * @param bottom bottom coordinate of the scissor box relative to the viewport + * @param width width of the scissor box + * @param height height of the scissor box + * + * @see unsetScissor + * @see View::setViewport + * @see View::setDynamicResolutionOptions + */ + void setScissor(uint32_t left, uint32_t bottom, uint32_t width, uint32_t height) noexcept; + + /** + * Returns the scissor rectangle to its default disabled setting. + * + * Currently the scissor is not compatible with dynamic resolution and should always be + * disabled when dynamic resolution is used. + * + * @see View::setDynamicResolutionOptions + */ + void unsetScissor() noexcept; + + /** + * Sets a polygon offset that will be applied to all renderables drawn with this material + * instance. + * + * The value of the offset is scale * dz + r * constant, where dz is the change in depth + * relative to the screen area of the triangle, and r is the smallest value that is guaranteed + * to produce a resolvable offset for a given implementation. This offset is added before the + * depth test. + * + * @warning using a polygon offset other than zero has a significant negative performance + * impact, as most implementations have to disable early depth culling. DO NOT USE unless + * absolutely necessary. + * + * @param scale scale factor used to create a variable depth offset for each triangle + * @param constant scale factor used to create a constant depth offset for each triangle + */ + void setPolygonOffset(float scale, float constant) noexcept; + + /** + * Overrides the minimum alpha value a fragment must have to not be discarded when the blend + * mode is MASKED. Defaults to 0.4 if it has not been set in the parent Material. The specified + * value should be between 0 and 1 and will be clamped if necessary. + */ + void setMaskThreshold(float threshold) noexcept; + + /** + * Gets the minimum alpha value a fragment must have to not be discarded when the blend + * mode is MASKED + */ + float getMaskThreshold() const noexcept; + + /** + * Sets the screen space variance of the filter kernel used when applying specular + * anti-aliasing. The default value is set to 0.15. The specified value should be between + * 0 and 1 and will be clamped if necessary. + */ + void setSpecularAntiAliasingVariance(float variance) noexcept; + + /** + * Gets the screen space variance of the filter kernel used when applying specular + * anti-aliasing. + */ + float getSpecularAntiAliasingVariance() const noexcept; + + /** + * Sets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. The default value is set to 0.2. The specified value should be between 0 + * and 1 and will be clamped if necessary. + */ + void setSpecularAntiAliasingThreshold(float threshold) noexcept; + + /** + * Gets the clamping threshold used to suppress estimation errors when applying specular + * anti-aliasing. + */ + float getSpecularAntiAliasingThreshold() const noexcept; + + /** + * Enables or disables double-sided lighting if the parent Material has double-sided capability, + * otherwise prints a warning. If double-sided lighting is enabled, backface culling is + * automatically disabled. + */ + void setDoubleSided(bool doubleSided) noexcept; + + /** + * Returns whether double-sided lighting is enabled when the parent Material has double-sided + * capability. + */ + bool isDoubleSided() const noexcept; + + /** + * Specifies how transparent objects should be rendered (default is DEFAULT). + */ + void setTransparencyMode(TransparencyMode mode) noexcept; + + /** + * Returns the transparency mode. + */ + TransparencyMode getTransparencyMode() const noexcept; + + /** + * Overrides the default triangle culling state that was set on the material. + */ + void setCullingMode(CullingMode culling) noexcept; + + /** + * Returns the face culling mode. + */ + CullingMode getCullingMode() const noexcept; + + /** + * Overrides the default color-buffer write state that was set on the material. + */ + void setColorWrite(bool enable) noexcept; + + /** + * Returns whether color write is enabled. + */ + bool isColorWriteEnabled() const noexcept; + + /** + * Overrides the default depth-buffer write state that was set on the material. + */ + void setDepthWrite(bool enable) noexcept; + + /** + * Returns whether depth write is enabled. + */ + bool isDepthWriteEnabled() const noexcept; + + /** + * Overrides the default depth testing state that was set on the material. + */ + void setDepthCulling(bool enable) noexcept; + + /** + * Overrides the default depth function state that was set on the material. + */ + void setDepthFunc(DepthFunc depthFunc) noexcept; + + /** + * Returns the depth function state. + */ + DepthFunc getDepthFunc() const noexcept; + + /** + * Returns whether depth culling is enabled. + */ + bool isDepthCullingEnabled() const noexcept; + + /** + * Overrides the default stencil-buffer write state that was set on the material. + */ + void setStencilWrite(bool enable) noexcept; + + /** + * Returns whether stencil write is enabled. + */ + bool isStencilWriteEnabled() const noexcept; + + /** + * Sets the stencil comparison function (default is StencilCompareFunc::A). + * + * It's possible to set separate stencil comparison functions; one for front-facing polygons, + * and one for back-facing polygons. The face parameter determines the comparison function(s) + * updated by this call. + */ + void setStencilCompareFunction(StencilCompareFunc func, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil fail operation (default is StencilOperation::KEEP). + * + * The stencil fail operation is performed to update values in the stencil buffer when the + * stencil test fails. + * + * It's possible to set separate stencil fail operations; one for front-facing polygons, and one + * for back-facing polygons. The face parameter determines the stencil fail operation(s) updated + * by this call. + */ + void setStencilOpStencilFail(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the depth fail operation (default is StencilOperation::KEEP). + * + * The depth fail operation is performed to update values in the stencil buffer when the depth + * test fails. + * + * It's possible to set separate depth fail operations; one for front-facing polygons, and one + * for back-facing polygons. The face parameter determines the depth fail operation(s) updated + * by this call. + */ + void setStencilOpDepthFail(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the depth-stencil pass operation (default is StencilOperation::KEEP). + * + * The depth-stencil pass operation is performed to update values in the stencil buffer when + * both the stencil test and depth test pass. + * + * It's possible to set separate depth-stencil pass operations; one for front-facing polygons, + * and one for back-facing polygons. The face parameter determines the depth-stencil pass + * operation(s) updated by this call. + */ + void setStencilOpDepthStencilPass(StencilOperation op, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil reference value (default is 0). + * + * The stencil reference value is the left-hand side for stencil comparison tests. It's also + * used as the replacement stencil value when StencilOperation is REPLACE. + * + * It's possible to set separate stencil reference values; one for front-facing polygons, and + * one for back-facing polygons. The face parameter determines the reference value(s) updated by + * this call. + */ + void setStencilReferenceValue(uint8_t value, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil read mask (default is 0xFF). + * + * The stencil read mask masks the bits of the values participating in the stencil comparison + * test- both the value read from the stencil buffer and the reference value. + * + * It's possible to set separate stencil read masks; one for front-facing polygons, and one for + * back-facing polygons. The face parameter determines the stencil read mask(s) updated by this + * call. + */ + void setStencilReadMask(uint8_t readMask, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + + /** + * Sets the stencil write mask (default is 0xFF). + * + * The stencil write mask masks the bits in the stencil buffer updated by stencil operations. + * + * It's possible to set separate stencil write masks; one for front-facing polygons, and one for + * back-facing polygons. The face parameter determines the stencil write mask(s) updated by this + * call. + */ + void setStencilWriteMask(uint8_t writeMask, + StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + +protected: + // prevent heap allocation + ~MaterialInstance() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_MATERIALINSTANCE_H diff --git a/package/ios/libs/filament/include/filament/MorphTargetBuffer.h b/package/ios/libs/filament/include/filament/MorphTargetBuffer.h new file mode 100644 index 00000000..655bb8d8 --- /dev/null +++ b/package/ios/libs/filament/include/filament/MorphTargetBuffer.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_MORPHTARGETBUFFER_H +#define TNT_FILAMENT_MORPHTARGETBUFFER_H + +#include + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * MorphTargetBuffer is used to hold morphing data (positions and tangents). + * + * Both positions and tangents are required. + * + */ +class UTILS_PUBLIC MorphTargetBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the morph targets in vertex counts. + * @param vertexCount Number of vertex counts the morph targets can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + /** + * Size of the morph targets in targets. + * @param count Number of targets the morph targets can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& count(size_t count) noexcept; + + /** + * Creates the MorphTargetBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this MorphTargetBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + MorphTargetBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FMorphTargetBuffer; + }; + + /** + * 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 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* UTILS_NONNULL positions, size_t count, size_t offset = 0); + + /** + * 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 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* UTILS_NONNULL positions, size_t count, size_t offset = 0); + + /** + * 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 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 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* UTILS_NONNULL tangents, size_t count, size_t offset = 0); + + /** + * Returns the vertex count of this MorphTargetBuffer. + * @return The number of vertices the MorphTargetBuffer holds. + */ + size_t getVertexCount() const noexcept; + + /** + * Returns the target count of this MorphTargetBuffer. + * @return The number of targets the MorphTargetBuffer holds. + */ + size_t getCount() const noexcept; + +protected: + // prevent heap allocation + ~MorphTargetBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_MORPHTARGETBUFFER_H diff --git a/package/ios/libs/filament/include/filament/Options.h b/package/ios/libs/filament/include/filament/Options.h new file mode 100644 index 00000000..3966053e --- /dev/null +++ b/package/ios/libs/filament/include/filament/Options.h @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_OPTIONS_H +#define TNT_FILAMENT_OPTIONS_H + +#include + +#include +#include + +#include + +#include + +namespace filament { + +class Texture; + +/** + * Generic quality level. + */ +enum class QualityLevel : uint8_t { + LOW, + MEDIUM, + HIGH, + ULTRA +}; + +enum class BlendMode : uint8_t { + OPAQUE, + TRANSLUCENT +}; + +/** + * Dynamic resolution can be used to either reach a desired target frame rate + * by lowering the resolution of a View, or to increase the quality when the + * rendering is faster than the target frame rate. + * + * This structure can be used to specify the minimum scale factor used when + * lowering the resolution of a View, and the maximum scale factor used when + * increasing the resolution for higher quality rendering. The scale factors + * can be controlled on each X and Y axis independently. By default, all scale + * factors are set to 1.0. + * + * enabled: enable or disables dynamic resolution on a View + * + * homogeneousScaling: by default the system scales the major axis first. Set this to true + * to force homogeneous scaling. + * + * minScale: the minimum scale in X and Y this View should use + * + * maxScale: the maximum scale in X and Y this View should use + * + * quality: upscaling quality. + * LOW: 1 bilinear tap, Medium: 4 bilinear taps, High: 9 bilinear taps (tent) + * + * \note + * Dynamic resolution is only supported on platforms where the time to render + * a frame can be measured accurately. Dynamic resolution is currently only + * supported on Android. + * + * @see Renderer::FrameRateOptions + * + */ +struct DynamicResolutionOptions { + math::float2 minScale = {0.5f, 0.5f}; //!< minimum scale factors in x and y %codegen_java_float% + math::float2 maxScale = {1.0f, 1.0f}; //!< maximum scale factors in x and y %codegen_java_float% + float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)] + bool enabled = false; //!< enable or disable dynamic resolution + bool homogeneousScaling = false; //!< set to true to force homogeneous scaling + + /** + * 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. + */ + QualityLevel quality = QualityLevel::LOW; +}; + +/** + * Options to control the bloom effect + * + * enabled: Enable or disable the bloom post-processing effect. Disabled by default. + * + * levels: Number of successive blurs to achieve the blur effect, the minimum is 3 and the + * maximum is 12. This value together with resolution influences the spread of the + * blur effect. This value can be silently reduced to accommodate the original + * image size. + * + * resolution: Resolution of bloom's minor axis. The minimum value is 2^levels and the + * the maximum is lower of the original resolution and 4096. This parameter is + * silently clamped to the minimum and maximum. + * It is highly recommended that this value be smaller than the target resolution + * after dynamic resolution is applied (horizontally and vertically). + * + * strength: how much of the bloom is added to the original image. Between 0 and 1. + * + * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original + * image (true). + * + * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons and is usually needed when a dirt texture is used. + * + * dirt: A dirt/scratch/smudges texture (that can be RGB), which gets added to the + * bloom effect. Smudges are visible where bloom occurs. Threshold must be + * enabled for the dirt effect to work properly. + * + * dirtStrength: Strength of the dirt texture. + */ +struct BloomOptions { + enum class BlendMode : uint8_t { + ADD, //!< Bloom is modulated by the strength parameter and added to the scene + INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter + }; + Texture* dirt = nullptr; //!< user provided dirt texture %codegen_skip_json% %codegen_skip_javascript% + float dirtStrength = 0.2f; //!< strength of the dirt texture %codegen_skip_json% %codegen_skip_javascript% + float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0 + uint32_t resolution = 384; //!< resolution of vertical axis (2^levels to 2048) + uint8_t levels = 6; //!< number of blur levels (1 to 11) + BlendMode blendMode = BlendMode::ADD; //!< how the bloom effect is applied + bool threshold = true; //!< whether to threshold the source + bool enabled = false; //!< enable or disable bloom + float highlight = 1000.0f; //!< limit highlights to this value before bloom [10, +inf] + + /** + * Bloom quality level. + * LOW (default): use a more optimized down-sampling filter, however there can be artifacts + * with dynamic resolution, this can be alleviated by using the homogenous mode. + * MEDIUM: Good balance between quality and performance. + * HIGH: In this mode the bloom resolution is automatically increased to avoid artifacts. + * This mode can be significantly slower on mobile, especially at high resolution. + * This mode greatly improves the anamorphic bloom. + */ + QualityLevel quality = QualityLevel::LOW; + + bool lensFlare = false; //!< enable screen-space lens flare + bool starburst = true; //!< enable starburst effect on lens flare + float chromaticAberration = 0.005f; //!< amount of chromatic aberration + uint8_t ghostCount = 4; //!< number of flare "ghosts" + float ghostSpacing = 0.6f; //!< spacing of the ghost in screen units [0, 1[ + float ghostThreshold = 10.0f; //!< hdr threshold for the ghosts + float haloThickness = 0.1f; //!< thickness of halo in vertical screen units, 0 to disable + float haloRadius = 0.4f; //!< radius of halo in vertical screen units [0, 0.5] + float haloThreshold = 10.0f; //!< hdr threshold for the halo +}; + +/** + * Options to control large-scale fog in the scene + */ +struct FogOptions { + /** + * Distance in world units [m] from the camera to where the fog starts ( >= 0.0 ) + */ + float distance = 0.0f; + + /** + * Distance in world units [m] after which the fog calculation is disabled. + * This can be used to exclude the skybox, which is desirable if it already contains clouds or + * fog. The default value is +infinity which applies the fog to everything. + * + * Note: The SkyBox is typically at a distance of 1e19 in world space (depending on the near + * plane distance and projection used though). + */ + float cutOffDistance = INFINITY; + + /** + * fog's maximum opacity between 0 and 1 + */ + float maximumOpacity = 1.0f; + + /** + * Fog's floor in world units [m]. This sets the "sea level". + */ + float height = 0.0f; + + /** + * How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m]. + * It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a + * factor 2.78 (e) change in fog density. + * + * A falloff of 0 means the fog density is constant everywhere and may result is slightly + * faster computations. + */ + float heightFalloff = 1.0f; + + /** + * Fog's color is used for ambient light in-scattering, a good value is + * to use the average of the ambient light, possibly tinted towards blue + * for outdoors environments. Color component's values should be between 0 and 1, values + * above one are allowed but could create a non energy-conservative fog (this is dependant + * on the IBL's intensity as well). + * + * We assume that our fog has no absorption and therefore all the light it scatters out + * becomes ambient light in-scattering and has lost all directionality, i.e.: scattering is + * isotropic. This somewhat simulates Rayleigh scattering. + * + * This value is used as a tint instead, when fogColorFromIbl is enabled. + * + * @see fogColorFromIbl + */ + LinearColor color = { 1.0f, 1.0f, 1.0f }; + + /** + * Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much + * light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces + * the incoming light to 37% of its original value. + * + * Note: The extinction factor is related to the fog density, it's usually some constant K times + * the density at sea level (more specifically at fog height). The constant K depends on + * the composition of the fog/atmosphere. + * + * For historical reason this parameter is called `density`. + */ + float density = 0.1f; + + /** + * Distance in world units [m] from the camera where the Sun in-scattering starts. + */ + float inScatteringStart = 0.0f; + + /** + * Very inaccurately simulates the Sun's in-scattering. That is, the light from the sun that + * is scattered (by the fog) towards the camera. + * Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100). + * Smaller values result is a larger scattering size. + */ + float inScatteringSize = -1.0f; + + /** + * The fog color will be sampled from the IBL in the view direction and tinted by `color`. + * Depending on the scene this can produce very convincing results. + * + * This simulates a more anisotropic phase-function. + * + * `fogColorFromIbl` is ignored when skyTexture is specified. + * + * @see skyColor + */ + bool fogColorFromIbl = false; + + /** + * skyTexture must be a mipmapped cubemap. When provided, the fog color will be sampled from + * this texture, higher resolution mip levels will be used for objects at the far clip plane, + * and lower resolution mip levels for objects closer to the camera. The skyTexture should + * typically be heavily blurred; a typical way to produce this texture is to blur the base + * level with a strong gaussian filter or even an irradiance filter and then generate mip + * levels as usual. How blurred the base level is somewhat of an artistic decision. + * + * This simulates a more anisotropic phase-function. + * + * `fogColorFromIbl` is ignored when skyTexture is specified. + * + * @see Texture + * @see fogColorFromIbl + */ + Texture* skyColor = nullptr; //!< %codegen_skip_json% %codegen_skip_javascript% + + /** + * Enable or disable large-scale fog + */ + bool enabled = false; +}; + +/** + * Options to control Depth of Field (DoF) effect in the scene. + * + * cocScale can be used to set the depth of field blur independently from the camera + * aperture, e.g. for artistic reasons. This can be achieved by setting: + * cocScale = cameraAperture / desiredDoFAperture + * + * @see Camera + */ +struct DepthOfFieldOptions { + enum class Filter : uint8_t { + NONE, + UNUSED, + MEDIAN + }; + float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur) + float cocAspectRatio = 1.0f; //!< width/height aspect ratio of the circle of confusion (simulate anamorphic lenses) + float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation) + bool enabled = false; //!< enable or disable depth of field effect + Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel + bool nativeResolution = false; //!< perform DoF processing at native resolution + /** + * 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. + * + * @{ + */ + uint8_t foregroundRingCount = 0; //!< number of kernel rings for foreground tiles + uint8_t backgroundRingCount = 0; //!< number of kernel rings for background tiles + uint8_t fastGatherRingCount = 0; //!< number of kernel rings for fast tiles + /** @}*/ + + /** + * 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. + */ + uint16_t maxForegroundCOC = 0; + + /** + * 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. + */ + uint16_t maxBackgroundCOC = 0; +}; + +/** + * Options to control the vignetting effect. + */ +struct VignetteOptions { + float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1 + float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0) + float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1 + LinearColorA color = {0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored + bool enabled = false; //!< enables or disables the vignette effect +}; + +/** + * Structure used to set the precision of the color buffer and related quality settings. + * + * @see setRenderQuality, getRenderQuality + */ +struct 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). + */ + QualityLevel hdrColorBuffer = QualityLevel::HIGH; +}; + +/** + * Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT) + * @see setAmbientOcclusionOptions() + */ +struct AmbientOcclusionOptions { + float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10. + float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive. + float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm. + float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0. + float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect. + float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering + QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO. + QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness + QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality + bool enabled = false; //!< enables or disables screen-space ambient occlusion + bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO + float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider + /** + * Screen Space Cone Tracing (SSCT) options + * 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 + 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 ssct; // %codegen_skip_javascript% %codegen_java_flatten% +}; + +/** + * Options for Multi-Sample Anti-aliasing (MSAA) + * @see setMultiSampleAntiAliasingOptions() + */ +struct MultiSampleAntiAliasingOptions { + bool enabled = false; //!< enables or disables msaa + + /** + * 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. + */ + uint8_t sampleCount = 4; + + /** + * custom resolve improves quality for HDR scenes, but may impact performance. + */ + bool customResolve = false; +}; + +/** + * Options for Temporal Anti-aliasing (TAA) + * Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process + * shaders to be recompiled. These options should be changed or set during initialization. + * `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time. + * + * `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state. + * see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information. + * + * @see setTemporalAntiAliasingOptions() + */ +struct TemporalAntiAliasingOptions { + float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother) + float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA). + float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2) + float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true. + bool enabled = false; //!< enables or disables temporal anti-aliasing + bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA] + + enum class BoxType : uint8_t { + AABB, //!< use an AABB neighborhood + VARIANCE, //!< use the variance of the neighborhood (not recommended) + AABB_VARIANCE //!< use both AABB and variance + }; + + enum class BoxClipping : uint8_t { + ACCURATE, //!< Accurate box clipping + CLAMP, //!< clamping + NONE //!< no rejections (use for debugging) + }; + + enum class JitterPattern : uint8_t { + RGSS_X4, //! 4-samples, rotated grid sampling + UNIFORM_HELIX_X4, //! 4-samples, uniform grid in helix sequence + HALTON_23_X8, //! 8-samples of halton 2,3 + HALTON_23_X16, //! 16-samples of halton 2,3 + HALTON_23_X32 //! 32-samples of halton 2,3 + }; + + bool filterHistory = true; //!< whether to filter the history buffer + bool filterInput = true; //!< whether to apply the reconstruction filter to the input + bool useYCoCg = false; //!< whether to use the YcoCg color-space for history rejection + BoxType boxType = BoxType::AABB; //!< type of color gamut box + BoxClipping boxClipping = BoxClipping::ACCURATE; //!< clipping algorithm + JitterPattern jitterPattern = JitterPattern::HALTON_23_X16; //! Jitter Pattern + float varianceGamma = 1.0f; //! High values increases ghosting artefact, lower values increases jittering, range [0.75, 1.25] + + bool preventFlickering = false; //!< adjust the feedback dynamically to reduce flickering + bool historyReprojection = true; //!< whether to apply history reprojection (debug option) +}; + +/** + * Options for Screen-space Reflections. + * @see setScreenSpaceReflectionsOptions() + */ +struct ScreenSpaceReflectionsOptions { + float thickness = 0.1f; //!< ray thickness, in world units + float bias = 0.01f; //!< bias, in world units, to prevent self-intersections + float maxDistance = 3.0f; //!< maximum distance, in world units, to raycast + float stride = 2.0f; //!< stride, in texels, for samples along the ray. + bool enabled = false; +}; + +/** + * Options for the screen-space guard band. + * A guard band can be enabled to avoid some artifacts towards the edge of the screen when + * using screen-space effects such as SSAO. Enabling the guard band reduces performance slightly. + * Currently the guard band can only be enabled or disabled. + */ +struct GuardBandOptions { + bool enabled = false; +}; + +/** + * List of available post-processing anti-aliasing techniques. + * @see setAntiAliasing, getAntiAliasing, setSampleCount + */ +enum class AntiAliasing : uint8_t { + NONE, //!< no anti aliasing performed as part of post-processing + FXAA //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default). +}; + +/** + * List of available post-processing dithering techniques. + */ +enum class Dithering : uint8_t { + NONE, //!< No dithering + TEMPORAL //!< Temporal dithering (default) +}; + +/** + * List of available shadow mapping techniques. + * @see setShadowType + */ +enum class ShadowType : uint8_t { + PCF, //!< percentage-closer filtered shadows (default) + VSM, //!< variance shadows + DPCF, //!< PCF with contact hardening simulation + PCSS, //!< PCF with soft shadows and contact hardening + PCFd, // for debugging only, don't use. +}; + +/** + * View-level options for VSM Shadowing. + * @see setVsmShadowOptions() + * @warning This API is still experimental and subject to change. + */ +struct 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. + */ + uint8_t anisotropy = 0; + + /** + * Whether to generate mipmaps for all VSM shadow maps. + */ + bool mipmapping = false; + + /** + * The number of MSAA samples to use when rendering VSM shadow maps. + * Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns + * off MSAA. + * Higher values may not be available depending on the underlying hardware. + */ + uint8_t msaaSamples = 1; + + /** + * Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits + * precision is rarely needed, but it does reduces light leaks as well as "fading" + * of the shadows in some situations. Setting highPrecision to true for a single + * shadow map will double the memory usage of all shadow maps. + */ + bool highPrecision = false; + + /** + * VSM minimum variance scale, must be positive. + */ + float minVarianceScale = 0.5f; + + /** + * VSM light bleeding reduction amount, between 0 and 1. + */ + float lightBleedReduction = 0.15f; +}; + +/** + * View-level options for DPCF and PCSS Shadowing. + * @see setSoftShadowOptions() + * @warning This API is still experimental and subject to change. + */ +struct SoftShadowOptions { + /** + * Globally scales the penumbra of all DPCF and PCSS shadows + * Acceptable values are greater than 0 + */ + float penumbraScale = 1.0f; + + /** + * 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. + */ + float penumbraRatioScale = 1.0f; +}; + +/** + * Options for stereoscopic (multi-eye) rendering. + */ +struct StereoscopicOptions { + bool enabled = false; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_OPTIONS_H diff --git a/package/ios/libs/filament/include/filament/RenderTarget.h b/package/ios/libs/filament/include/filament/RenderTarget.h new file mode 100644 index 00000000..fc76111d --- /dev/null +++ b/package/ios/libs/filament/include/filament/RenderTarget.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2019 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_RENDERTARGET_H +#define TNT_FILAMENT_RENDERTARGET_H + +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FRenderTarget; + +class Engine; +class Texture; + +/** + * An offscreen render target that can be associated with a View and contains + * weak references to a set of attached Texture objects. + * + * RenderTarget is intended to be used with the View's post-processing disabled for the most part. + * especially when a DEPTH attachment is also used (see Builder::texture()). + * + * Custom RenderTarget are ultimately intended to render into textures that might be used during + * the main render pass. + * + * Clients are responsible for the lifetime of all associated Texture attachments. + * + * @see View + */ +class UTILS_PUBLIC RenderTarget : public FilamentAPI { + struct BuilderDetails; + +public: + using CubemapFace = backend::TextureCubemapFace; + + /** Minimum number of color attachment supported */ + static constexpr uint8_t MIN_SUPPORTED_COLOR_ATTACHMENTS_COUNT = + backend::MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; + + /** Maximum number of color attachment supported */ + static constexpr uint8_t MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT = + backend::MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; + + /** + * Attachment identifiers + */ + enum class AttachmentPoint : uint8_t { + COLOR0 = 0, //!< identifies the 1st color attachment + COLOR1 = 1, //!< identifies the 2nd color attachment + COLOR2 = 2, //!< identifies the 3rd color attachment + COLOR3 = 3, //!< identifies the 4th color attachment + COLOR4 = 4, //!< identifies the 5th color attachment + COLOR5 = 5, //!< identifies the 6th color attachment + COLOR6 = 6, //!< identifies the 7th color attachment + COLOR7 = 7, //!< identifies the 8th color attachment + DEPTH = MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT, //!< identifies the depth attachment + COLOR = COLOR0, //!< identifies the 1st color attachment + }; + + //! Use Builder to construct a RenderTarget object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Sets a texture to a given attachment point. + * + * When using a DEPTH attachment, it is important to always disable post-processing + * in the View. Failing to do so will cause the DEPTH attachment to be ignored in most + * cases. + * + * When the intention is to keep the content of the DEPTH attachment after rendering, + * Usage::SAMPLEABLE must be set on the DEPTH attachment, otherwise the content of the + * DEPTH buffer may be discarded. + * + * @param attachment The attachment point of the texture. + * @param texture The associated texture object. + * @return A reference to this Builder for chaining calls. + */ + Builder& texture(AttachmentPoint attachment, Texture* UTILS_NULLABLE texture) noexcept; + + /** + * Sets the mipmap level for a given attachment point. + * + * @param attachment The attachment point of the texture. + * @param level The associated mipmap level, 0 by default. + * @return A reference to this Builder for chaining calls. + */ + Builder& mipLevel(AttachmentPoint attachment, uint8_t level) noexcept; + + /** + * Sets the cubemap face for a given attachment point. + * + * @param attachment The attachment point. + * @param face The associated cubemap face. + * @return A reference to this Builder for chaining calls. + */ + Builder& face(AttachmentPoint attachment, CubemapFace face) noexcept; + + /** + * Sets the layer for a given attachment point (for 3D textures). + * + * @param attachment The attachment point. + * @param layer The associated cubemap layer. + * @return A reference to this Builder for chaining calls. + */ + Builder& layer(AttachmentPoint attachment, uint32_t layer) noexcept; + + /** + * Creates the RenderTarget object and returns a pointer to it. + * + * @return pointer to the newly created object. + */ + RenderTarget* UTILS_NONNULL build(Engine& engine); + + private: + friend class FRenderTarget; + }; + + /** + * Gets the texture set on the given attachment point + * @param attachment Attachment point + * @return A Texture object or nullptr if no texture is set for this attachment point + */ + Texture* UTILS_NULLABLE getTexture(AttachmentPoint attachment) const noexcept; + + /** + * Returns the mipmap level set on the given attachment point + * @param attachment Attachment point + * @return the mipmap level set on the given attachment point + */ + uint8_t getMipLevel(AttachmentPoint attachment) const noexcept; + + /** + * Returns the face of a cubemap set on the given attachment point + * @param attachment Attachment point + * @return A cubemap face identifier. This is only relevant if the attachment's texture is + * a cubemap. + */ + CubemapFace getFace(AttachmentPoint attachment) const noexcept; + + /** + * Returns the texture-layer set on the given attachment point + * @param attachment Attachment point + * @return A texture layer. This is only relevant if the attachment's texture is a 3D texture. + */ + uint32_t getLayer(AttachmentPoint attachment) const noexcept; + + /** + * Returns the number of color attachments usable by this instance of Engine. This method is + * guaranteed to return at least MIN_SUPPORTED_COLOR_ATTACHMENTS_COUNT and at most + * MAX_SUPPORTED_COLOR_ATTACHMENTS_COUNT. + * @return Number of color attachments usable in a render target. + */ + uint8_t getSupportedColorAttachmentsCount() const noexcept; + +protected: + // prevent heap allocation + ~RenderTarget() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERTARGET_H diff --git a/package/ios/libs/filament/include/filament/RenderableManager.h b/package/ios/libs/filament/include/filament/RenderableManager.h new file mode 100644 index 00000000..bec39e4a --- /dev/null +++ b/package/ios/libs/filament/include/filament/RenderableManager.h @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_RENDERABLEMANAGER_H +#define TNT_FILAMENT_RENDERABLEMANAGER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class BufferObject; +class Engine; +class IndexBuffer; +class MaterialInstance; +class Renderer; +class SkinningBuffer; +class VertexBuffer; +class Texture; +class InstanceBuffer; + +class FEngine; +class FRenderPrimitive; +class FRenderableManager; + +/** + * Factory and manager for \em renderables, which are entities that can be drawn. + * + * Renderables are bundles of \em primitives, each of which has its own geometry and material. All + * primitives in a particular renderable share a set of rendering attributes, such as whether they + * cast shadows or use vertex skinning. + * + * Usage example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto renderable = utils::EntityManager::get().create(); + * + * RenderableManager::Builder(1) + * .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + * .material(0, matInstance) + * .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vertBuffer, indBuffer, 0, 3) + * .receiveShadows(false) + * .build(engine, renderable); + * + * scene->addEntity(renderable); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To modify the state of an existing renderable, clients should first use RenderableManager + * to get a temporary handle called an \em instance. The instance can then be used to get or set + * the renderable's state. Please note that instances are ephemeral; clients should store entities, + * not instances. + * + * - For details about constructing renderables, see RenderableManager::Builder. + * - To associate a 4x4 transform with an entity, see TransformManager. + * - To associate a human-readable label with an entity, see utils::NameComponentManager. + */ +class UTILS_PUBLIC RenderableManager : public FilamentAPI { + struct BuilderDetails; + +public: + using Instance = utils::EntityInstance; + using PrimitiveType = backend::PrimitiveType; + + /** + * Checks if the given entity already has a renderable component. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * Gets a temporary handle that can be used to access the renderable state. + * + * @return Non-zero handle if the entity has a renderable component, 0 otherwise. + */ + Instance getInstance(utils::Entity e) const noexcept; + + /** + * @return the number of Components + */ + size_t getComponentCount() const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * The transformation associated with a skinning joint. + * + * Clients can specify bones either using this quat-vec3 pair, or by using 4x4 matrices. + */ + struct Bone { + math::quatf unitQuaternion = { 1.f, 0.f, 0.f, 0.f }; + math::float3 translation = { 0.f, 0.f, 0.f }; + float reserved = 0; + }; + + /** + * Adds renderable components to entities using a builder pattern. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + enum Result { Error = -1, Success = 0 }; + + /** + * Default render channel + * @see Builder::channel() + */ + static constexpr uint8_t DEFAULT_CHANNEL = 2u; + + /** + * Creates a builder for renderable components. + * + * @param count the number of primitives that will be supplied to the builder + * + * Note that builders typically do not have a long lifetime since clients should discard + * them after calling build(). For a usage example, see RenderableManager. + */ + explicit Builder(size_t count) noexcept; + + /*! \cond PRIVATE */ + Builder(Builder const& rhs) = delete; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder& rhs) = delete; + Builder& operator=(Builder&& rhs) noexcept; + /*! \endcond */ + + /** + * Specifies the geometry data for a primitive. + * + * Filament primitives must have an associated VertexBuffer and IndexBuffer. Typically, each + * primitive is specified with a pair of daisy-chained calls: \c geometry(...) and \c + * material(...). + * + * @param index zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param type specifies the topology of the primitive (e.g., \c RenderableManager::PrimitiveType::TRIANGLES) + * @param vertices specifies the vertex buffer, which in turn specifies a set of attributes + * @param indices specifies the index buffer (either u16 or u32) + * @param offset specifies where in the index buffer to start reading (expressed as a number of indices) + * @param minIndex specifies the minimum index contained in the index buffer + * @param maxIndex specifies the maximum index contained in the index buffer + * @param count number of indices to read (for triangles, this should be a multiple of 3) + */ + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t minIndex, size_t maxIndex, size_t count) noexcept; + + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t count) noexcept; //!< \overload + + Builder& geometry(size_t index, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices) noexcept; //!< \overload + + /** + * Binds a material instance to the specified primitive. + * + * If no material is specified for a given primitive, Filament will fall back to a basic + * default material. + * + * The MaterialInstance's material must have a feature level equal or lower to the engine's + * selected feature level. + * + * @param index zero-based index of the primitive, must be less than the count passed to + * Builder constructor + * @param materialInstance the material to bind + * + * @see Engine::setActiveFeatureLevel + */ + Builder& material(size_t index, + MaterialInstance const* UTILS_NONNULL materialInstance) noexcept; + + /** + * The axis-aligned bounding box of the renderable. + * + * This is an object-space AABB used for frustum culling. For skinning and morphing, this + * should encompass all possible vertex positions. It is mandatory unless culling is + * disabled for the renderable. + * + * \see computeAABB() + */ + Builder& boundingBox(const Box& axisAlignedBoundingBox) noexcept; + + /** + * Sets bits in a visibility mask. By default, this is 0x1. + * + * This feature provides a simple mechanism for hiding and showing groups of renderables + * in a Scene. See View::setVisibleLayers(). + * + * For example, to set bit 1 and reset bits 0 and 2 while leaving all other bits unaffected, + * do: `builder.layerMask(7, 2)`. + * + * To change this at run time, see RenderableManager::setLayerMask. + * + * @param select the set of bits to affect + * @param values the replacement values for the affected bits + */ + Builder& layerMask(uint8_t select, uint8_t values) noexcept; + + /** + * Provides coarse-grained control over draw order. + * + * In general Filament reserves the right to re-order renderables to allow for efficient + * rendering. However clients can control ordering at a coarse level using \em priority. + * The priority is applied separately for opaque and translucent objects, that is, opaque + * objects are always drawn before translucent objects regardless of the priority. + * + * For example, this could be used to draw a semitransparent HUD on top of everything, + * without using a separate View. Note that priority is completely orthogonal to + * Builder::layerMask, which merely controls visibility. + * + * The Skybox always using the lowest priority, so it's drawn last, which may improve + * performance. + * + * @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority + * (rendered last). + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::channel() + * @see RenderableManager::setPriority() + * @see RenderableManager::setBlendOrderAt() + */ + Builder& priority(uint8_t priority) noexcept; + + /** + * Set the channel this renderable is associated to. There can be 4 channels. + * All renderables in a given channel are rendered together, regardless of anything else. + * They are sorted as usual within a channel. + * Channels work similarly to priorities, except that they enforce the strongest ordering. + * + * Channels 0 and 1 may not have render primitives using a material with `refractionType` + * set to `screenspace`. + * + * @param channel clamped to the range [0..3], defaults to 2. + * + * @return Builder reference for chaining calls. + * + * @see Builder::blendOrder() + * @see Builder::priority() + * @see RenderableManager::setBlendOrderAt() + */ + Builder& channel(uint8_t channel) noexcept; + + /** + * Controls frustum culling, true by default. + * + * \note Do not confuse frustum culling with backface culling. The latter is controlled via + * the material. + */ + Builder& culling(bool enable) noexcept; + + /** + * Enables or disables a light channel. Light channel 0 is enabled by default. + * + * @param channel Light channel to enable or disable, between 0 and 7. + * @param enable Whether to enable or disable the light channel. + */ + Builder& lightChannel(unsigned int channel, bool enable = true) noexcept; + + /** + * Controls if this renderable casts shadows, false by default. + * + * If the View's shadow type is set to ShadowType::VSM, castShadows should only be disabled + * if either is true: + * - receiveShadows is also disabled + * - the object is guaranteed to not cast shadows on itself or other objects (for example, + * a ground plane) + */ + Builder& castShadows(bool enable) noexcept; + + /** + * Controls if this renderable receives shadows, true by default. + */ + Builder& receiveShadows(bool enable) noexcept; + + /** + * Controls if this renderable uses screen-space contact shadows. This is more + * expensive but can improve the quality of shadows, especially in large scenes. + * (off by default). + */ + Builder& screenSpaceContactShadows(bool enable) noexcept; + + /** + * Allows bones to be swapped out and shared using SkinningBuffer. + * + * If skinning buffer mode is enabled, clients must call setSkinningBuffer() rather than + * setBones(). This allows sharing of data between renderables. + * + * @param enabled If true, enables buffer object mode. False by default. + */ + Builder& enableSkinningBuffers(bool enabled = true) noexcept; + + /** + * Controls if this renderable is affected by the large-scale fog. + * @param enabled If true, enables large-scale fog on this object. Disables it otherwise. + * True by default. + * @return A reference to this Builder for chaining calls. + */ + Builder& fog(bool enabled = true) noexcept; + + /** + * Enables GPU vertex skinning for up to 255 bones, 0 by default. + * + * Skinning Buffer mode must be enabled. + * + * Each vertex can be affected by up to 4 bones simultaneously. The attached + * VertexBuffer must provide data in the \c BONE_INDICES slot (uvec4) and the + * \c BONE_WEIGHTS slot (float4). + * + * See also RenderableManager::setSkinningBuffer() or SkinningBuffer::setBones(), + * which can be called on a per-frame basis to advance the animation. + * + * @param skinningBuffer nullptr to disable, otherwise the SkinningBuffer to use + * @param count 0 to disable, otherwise the number of bone transforms (up to 255) + * @param offset offset in the SkinningBuffer + */ + Builder& skinning(SkinningBuffer* UTILS_NONNULL skinningBuffer, + size_t count, size_t offset) noexcept; + + + /** + * Enables GPU vertex skinning for up to 255 bones, 0 by default. + * + * Skinning Buffer mode must be disabled. + * + * Each vertex can be affected by up to 4 bones simultaneously. The attached + * VertexBuffer must provide data in the \c BONE_INDICES slot (uvec4) and the + * \c BONE_WEIGHTS slot (float4). + * + * See also RenderableManager::setBones(), which can be called on a per-frame basis + * to advance the animation. + * + * @param boneCount 0 to disable, otherwise the number of bone transforms (up to 255) + * @param transforms the initial set of transforms (one for each bone) + */ + Builder& skinning(size_t boneCount, math::mat4f const* UTILS_NONNULL transforms) noexcept; + Builder& skinning(size_t boneCount, Bone const* UTILS_NONNULL bones) noexcept; //!< \overload + Builder& skinning(size_t boneCount) noexcept; //!< \overload + + /** + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs per vertex bonesPerVertex is not limited to 4 bones. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data must be rectangular and number of bone pairs must be same for all vertices of this + * primitive. + * The data is arranged sequentially, all bone pairs for the first vertex, then for the + * second vertex, and so on. + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeights pairs of bone index and bone weight for all vertices + * sequentially + * @param count number of all pairs, must be a multiple of vertexCount of the primitive + * count = vertexCount * bonesPerVertex + * @param bonesPerVertex number of bone pairs, same for all vertices of the primitive + * + * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex, + math::float2 const* UTILS_NONNULL indicesAndWeights, + size_t count, size_t bonesPerVertex) noexcept; + + /** + * Define bone indices and weights "pairs" for vertex skinning as a float2. + * The unsigned int(pair.x) defines index of the bone and pair.y is the bone weight. + * The pairs substitute \c BONE_INDICES and the \c BONE_WEIGHTS defined in the VertexBuffer. + * Both ways of indices and weights definition must not be combined in one primitive. + * Number of pairs is not limited to 4 bones per vertex. + * Vertex buffer used for \c primitiveIndex must be set for advance skinning. + * All bone weights of one vertex should sum to one. Otherwise they will be normalized. + * Data doesn't have to be rectangular and number of pairs per vertices of primitive can be + * variable. + * The vector of the vertices contains the vectors of the pairs + * + * @param primitiveIndex zero-based index of the primitive, must be less than the primitive + * count passed to Builder constructor + * @param indicesAndWeightsVectors pairs of bone index and bone weight for all vertices of + * the primitive sequentially + * + * @return Builder reference for chaining calls. + * + * @see VertexBuffer:Builder:advancedSkinning + */ + Builder& boneIndicesAndWeights(size_t primitiveIndex, + utils::FixedCapacityVector< + utils::FixedCapacityVector> indicesAndWeightsVector) noexcept; + /** + * Controls if the renderable has vertex morphing targets, zero by default. This is + * required to enable GPU morphing. + * + * Filament supports two morphing modes: standard (default) and legacy. + * + * For standard morphing, A MorphTargetBuffer must be created and provided via + * RenderableManager::setMorphTargetBufferAt(). Standard morphing supports up to + * \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets. + * + * For legacy morphing, the attached VertexBuffer must provide data in the + * appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only + * supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must + * be enabled on the material definition: either via the legacyMorphing material attribute + * or by calling filamat::MaterialBuilder::useLegacyMorphing(). + * + * See also RenderableManager::setMorphWeights(), which can be called on a per-frame basis + * to advance the animation. + */ + Builder& morphing(size_t targetCount) noexcept; + + /** + * Specifies the morph target buffer for a primitive. + * + * The morph target buffer must have an associated renderable and geometry. Two conditions + * must be met: + * 1. The number of morph targets in the buffer must equal the renderable's morph target + * count. + * 2. The vertex count of each morph target must equal the geometry's vertex count. + * + * @param level the level of detail (lod), only 0 can be specified + * @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param morphTargetBuffer specifies the morph target buffer + * @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices) + * @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3) + */ + Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, + size_t offset, size_t count) noexcept; + + inline Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept; + + /** + * Sets the drawing order for blended primitives. The drawing order is either global or + * local (default) to this Renderable. In either case, the Renderable priority takes + * precedence. + * + * @param primitiveIndex the primitive of interest + * @param order draw order number (0 by default). Only the lowest 15 bits are used. + * + * @return Builder reference for chaining calls. + * + * @see globalBlendOrderEnabled + */ + Builder& blendOrder(size_t primitiveIndex, uint16_t order) noexcept; + + /** + * Sets whether the blend order is global or local to this Renderable (by default). + * + * @param primitiveIndex the primitive of interest + * @param enabled true for global, false for local blend ordering. + * + * @return Builder reference for chaining calls. + * + * @see blendOrder + */ + Builder& globalBlendOrderEnabled(size_t primitiveIndex, bool enabled) noexcept; + + /** + * Specifies the number of draw instances of this renderable. The default is 1 instance and + * the maximum number of instances allowed is 32767. 0 is invalid. + * + * All instances are culled using the same bounding box, so care must be taken to make + * sure all instances render inside the specified bounding box. + * + * The material must set its `instanced` parameter to `true` in order to use + * getInstanceIndex() in the vertex or fragment shader to get the instance index and + * possibly adjust the position or transform. + * + * @param instanceCount the number of instances silently clamped between 1 and 32767. + */ + Builder& instances(size_t instanceCount) noexcept; + + /** + * Specifies the number of draw instances of this renderable and an \c InstanceBuffer + * containing their local transforms. The default is 1 instance and the maximum number of + * instances allowed when supplying transforms is given by + * \c Engine::getMaxAutomaticInstances (64 on most platforms). 0 is invalid. The + * \c InstanceBuffer must not be destroyed before this renderable. + * + * All instances are culled using the same bounding box, so care must be taken to make + * sure all instances render inside the specified bounding box. + * + * The material must set its `instanced` parameter to `true` in order to use + * \c getInstanceIndex() in the vertex or fragment shader to get the instance index. + * + * Only the \c VERTEX_DOMAIN_OBJECT vertex domain is supported. + * + * The local transforms of each instance can be updated with + * \c InstanceBuffer::setLocalTransforms. + * + * \see InstanceBuffer + * \see instances(size_t, * math::mat4f const*) + * @param instanceCount the number of instances, silently clamped between 1 and + * the result of Engine::getMaxAutomaticInstances(). + * @param instanceBuffer an InstanceBuffer containing at least instanceCount transforms + */ + Builder& instances(size_t instanceCount, + InstanceBuffer* UTILS_NONNULL instanceBuffer) noexcept; + + /** + * Adds the Renderable component to an entity. + * + * @param engine Reference to the filament::Engine to associate this Renderable with. + * @param entity Entity to add the Renderable component to. + * @return Success if the component was created successfully, Error otherwise. + * + * If exceptions are disabled and an error occurs, this function is a no-op. + * Success can be checked by looking at the return value. + * + * If this component already exists on the given entity and the construction is successful, + * it is first destroyed as if destroy(utils::Entity e) was called. In case of error, + * the existing component is unmodified. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Result build(Engine& engine, utils::Entity entity); + + private: + friend class FEngine; + friend class FRenderPrimitive; + friend class FRenderableManager; + struct Entry { + VertexBuffer* UTILS_NULLABLE vertices = nullptr; + IndexBuffer* UTILS_NULLABLE indices = nullptr; + size_t offset = 0; + size_t count = 0; + MaterialInstance const* UTILS_NULLABLE materialInstance = nullptr; + PrimitiveType type = PrimitiveType::TRIANGLES; + uint16_t blendOrder = 0; + bool globalBlendOrderEnabled = false; + struct { + MorphTargetBuffer* UTILS_NULLABLE buffer = nullptr; + size_t offset = 0; + size_t count = 0; + } morphing; + }; + }; + + /** + * Destroys the renderable component in the given entity. + */ + void destroy(utils::Entity e) noexcept; + + /** + * Changes the bounding box used for frustum culling. + * + * \see Builder::boundingBox() + * \see RenderableManager::getAxisAlignedBoundingBox() + */ + void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept; + + /** + * Changes the visibility bits. + * + * \see Builder::layerMask() + * \see View::setVisibleLayers(). + * \see RenderableManager::getLayerMask() + */ + void setLayerMask(Instance instance, uint8_t select, uint8_t values) noexcept; + + /** + * Changes the coarse-level draw ordering. + * + * \see Builder::priority(). + */ + void setPriority(Instance instance, uint8_t priority) noexcept; + + /** + * Changes the channel a renderable is associated to. + * + * \see Builder::channel(). + */ + void setChannel(Instance instance, uint8_t channel) noexcept; + + /** + * Changes whether or not frustum culling is on. + * + * \see Builder::culling() + */ + void setCulling(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the large-scale fog is applied to this renderable + * @see Builder::fog() + */ + void setFogEnabled(Instance instance, bool enable) noexcept; + + /** + * Returns whether large-scale fog is enabled for this renderable. + * @return True if fog is enabled for this renderable. + * @see Builder::fog() + */ + bool getFogEnabled(Instance instance) const noexcept; + + /** + * Enables or disables a light channel. + * Light channel 0 is enabled by default. + * + * \see Builder::lightChannel() + */ + void setLightChannel(Instance instance, unsigned int channel, bool enable) noexcept; + + /** + * Returns whether a light channel is enabled on a specified renderable. + * @param instance Instance of the component obtained from getInstance(). + * @param channel Light channel to query + * @return true if the light channel is enabled, false otherwise + */ + bool getLightChannel(Instance instance, unsigned int channel) const noexcept; + + /** + * Changes whether or not the renderable casts shadows. + * + * \see Builder::castShadows() + */ + void setCastShadows(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the renderable can receive shadows. + * + * \see Builder::receiveShadows() + */ + void setReceiveShadows(Instance instance, bool enable) noexcept; + + /** + * Changes whether or not the renderable can use screen-space contact shadows. + * + * \see Builder::screenSpaceContactShadows() + */ + void setScreenSpaceContactShadows(Instance instance, bool enable) noexcept; + + /** + * Checks if the renderable can cast shadows. + * + * \see Builder::castShadows(). + */ + bool isShadowCaster(Instance instance) const noexcept; + + /** + * Checks if the renderable can receive shadows. + * + * \see Builder::receiveShadows(). + */ + bool isShadowReceiver(Instance instance) const noexcept; + + /** + * Updates the bone transforms in the range [offset, offset + boneCount). + * The bones must be pre-allocated using Builder::skinning(). + */ + void setBones(Instance instance, Bone const* UTILS_NONNULL transforms, + size_t boneCount = 1, size_t offset = 0); + + void setBones(Instance instance, math::mat4f const* UTILS_NONNULL transforms, + size_t boneCount = 1, size_t offset = 0); //!< \overload + + /** + * Associates a region of a SkinningBuffer to a renderable instance + * + * Note: due to hardware limitations offset + 256 must be smaller or equal to + * skinningBuffer->getBoneCount() + * + * @param instance Instance of the component obtained from getInstance(). + * @param skinningBuffer skinning buffer to associate to the instance + * @param count Size of the region in bones, must be smaller or equal to 256. + * @param offset Start offset of the region in bones + */ + void setSkinningBuffer(Instance instance, SkinningBuffer* UTILS_NONNULL skinningBuffer, + size_t count, size_t offset); + + /** + * Updates the vertex morphing weights on a renderable, all zeroes by default. + * + * The renderable must be built with morphing enabled, see Builder::morphing(). In legacy + * morphing mode, only the first 4 weights are considered. + * + * @param instance Instance of the component obtained from getInstance(). + * @param weights Pointer to morph target weights to be update. + * @param count Number of morph target weights. + * @param offset Index of the first morph target weight to set at instance. + */ + void setMorphWeights(Instance instance, + float const* UTILS_NONNULL weights, size_t count, size_t offset = 0); + + /** + * Associates a MorphTargetBuffer to the given primitive. + */ + void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, size_t offset, size_t count); + + /** + * Utility method to change a MorphTargetBuffer to the given primitive + */ + inline void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer); + + /** + * Get a MorphTargetBuffer to the given primitive or null if it doesn't exist. + */ + MorphTargetBuffer* UTILS_NULLABLE getMorphTargetBufferAt(Instance instance, + uint8_t level, size_t primitiveIndex) const noexcept; + + /** + * Gets the number of morphing in the given entity. + */ + size_t getMorphTargetCount(Instance instance) const noexcept; + + /** + * Gets the bounding box used for frustum culling. + * + * \see Builder::boundingBox() + * \see RenderableManager::setAxisAlignedBoundingBox() + */ + const Box& getAxisAlignedBoundingBox(Instance instance) const noexcept; + + /** + * Get the visibility bits. + * + * \see Builder::layerMask() + * \see View::setVisibleLayers(). + * \see RenderableManager::getLayerMask() + */ + uint8_t getLayerMask(Instance instance) const noexcept; + + /** + * Gets the immutable number of primitives in the given renderable. + */ + size_t getPrimitiveCount(Instance instance) const noexcept; + + /** + * Changes the material instance binding for the given primitive. + * + * The MaterialInstance's material must have a feature level equal or lower to the engine's + * selected feature level. + * + * @exception utils::PreConditionPanic if the engine doesn't support the material's + * feature level. + * + * @see Builder::material() + * @see Engine::setActiveFeatureLevel + */ + void setMaterialInstanceAt(Instance instance, + size_t primitiveIndex, MaterialInstance const* UTILS_NONNULL materialInstance); + + /** + * Retrieves the material instance that is bound to the given primitive. + */ + MaterialInstance* UTILS_NULLABLE getMaterialInstanceAt( + Instance instance, size_t primitiveIndex) const noexcept; + + /** + * Changes the geometry for the given primitive. + * + * \see Builder::geometry() + */ + void setGeometryAt(Instance instance, size_t primitiveIndex, PrimitiveType type, + VertexBuffer* UTILS_NONNULL vertices, + IndexBuffer* UTILS_NONNULL indices, + size_t offset, size_t count) noexcept; + + /** + * Changes the drawing order for blended primitives. The drawing order is either global or + * local (default) to this Renderable. In either case, the Renderable priority takes precedence. + * + * @param instance the renderable of interest + * @param primitiveIndex the primitive of interest + * @param order draw order number (0 by default). Only the lowest 15 bits are used. + * + * @see Builder::blendOrder(), setGlobalBlendOrderEnabledAt() + */ + void setBlendOrderAt(Instance instance, size_t primitiveIndex, uint16_t order) noexcept; + + /** + * Changes whether the blend order is global or local to this Renderable (by default). + * + * @param instance the renderable of interest + * @param primitiveIndex the primitive of interest + * @param enabled true for global, false for local blend ordering. + * + * @see Builder::globalBlendOrderEnabled(), setBlendOrderAt() + */ + void setGlobalBlendOrderEnabledAt(Instance instance, size_t primitiveIndex, bool enabled) noexcept; + + /** + * Retrieves the set of enabled attribute slots in the given primitive's VertexBuffer. + */ + AttributeBitset getEnabledAttributesAt(Instance instance, size_t primitiveIndex) const noexcept; + + /*! \cond PRIVATE */ + template + struct is_supported_vector_type { + using type = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type; + }; + + template + struct is_supported_index_type { + using type = typename std::enable_if< + std::is_same::value || + std::is_same::value + >::type; + }; + /*! \endcond */ + + /** + * Utility method that computes the axis-aligned bounding box from a set of vertices. + * + * - The index type must be \c uint16_t or \c uint32_t. + * - The vertex type must be \c float4, \c half4, \c float3, or \c half3. + * - For 4-component vertices, the w component is ignored (implicitly replaced with 1.0). + */ + template::type, + typename = typename is_supported_index_type::type> + static Box computeAABB( + VECTOR const* UTILS_NONNULL vertices, + INDEX const* UTILS_NONNULL indices, size_t count, + size_t stride = sizeof(VECTOR)) noexcept; + +protected: + // prevent heap allocation + ~RenderableManager() = default; +}; + +RenderableManager::Builder& RenderableManager::Builder::morphing( + uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept { + return morphing(level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); +} + +void RenderableManager::setMorphTargetBufferAt( + Instance instance, uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) { + setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); +} + +template +Box RenderableManager::computeAABB( + VECTOR const* UTILS_NONNULL vertices, + INDEX const* UTILS_NONNULL indices, + size_t count, size_t stride) noexcept { + math::float3 bmin(FLT_MAX); + math::float3 bmax(-FLT_MAX); + for (size_t i = 0; i < count; ++i) { + VECTOR const* p = reinterpret_cast( + (char const*)vertices + indices[i] * stride); + const math::float3 v(p->x, p->y, p->z); + bmin = min(bmin, v); + bmax = max(bmax, v); + } + return Box().set(bmin, bmax); +} + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERABLEMANAGER_H diff --git a/package/ios/libs/filament/include/filament/Renderer.h b/package/ios/libs/filament/include/filament/Renderer.h new file mode 100644 index 00000000..fdc291b1 --- /dev/null +++ b/package/ios/libs/filament/include/filament/Renderer.h @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_RENDERER_H +#define TNT_FILAMENT_RENDERER_H + +#include + +#include + +#include + +#include + +namespace filament { + +class Engine; +class RenderTarget; +class SwapChain; +class View; +class Viewport; + +namespace backend { +class PixelBufferDescriptor; +} // namespace backend + +/** + * A Renderer instance represents an operating system's window. + * + * Typically, applications create a Renderer per window. The Renderer generates drawing commands + * for the render thread and manages frame latency. + * + * A Renderer generates drawing commands from a View, itself containing a Scene description. + * + * Creation and Destruction + * ======================== + * + * A Renderer is created using Engine.createRenderer() and destroyed using + * Engine.destroy(const Renderer*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * Renderer* renderer = engine->createRenderer(); + * engine->destroy(&renderer); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see Engine, View + */ +class UTILS_PUBLIC Renderer : public FilamentAPI { +public: + + /** + * Use DisplayInfo to set important Display properties. This is used to achieve correct + * frame pacing and dynamic resolution scaling. + */ + struct DisplayInfo { + // refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing. + float refreshRate = 60.0f; + + UTILS_DEPRECATED uint64_t presentationDeadlineNanos = 0; + UTILS_DEPRECATED uint64_t vsyncOffsetNanos = 0; + }; + + /** + * Use FrameRateOptions to set the desired frame rate and control how quickly the system + * reacts to GPU load changes. + * + * interval: desired frame interval in multiple of the refresh period, set in DisplayInfo + * (as 1 / DisplayInfo::refreshRate) + * + * The parameters below are relevant when some Views are using dynamic resolution scaling: + * + * headRoomRatio: additional headroom for the GPU as a ratio of the targetFrameTime. + * Useful for taking into account constant costs like post-processing or + * GPU drivers on different platforms. + * history: History size. higher values, tend to filter more (clamped to 31) + * scaleRate: rate at which the gpu load is adjusted to reach the target frame rate + * This value can be computed as 1 / N, where N is the number of frames + * needed to reach 64% of the target scale factor. + * Higher values make the dynamic resolution react faster. + * + * @see View::DynamicResolutionOptions + * @see Renderer::DisplayInfo + * + */ + struct FrameRateOptions { + float headRoomRatio = 0.0f; //!< additional headroom for the GPU + float scaleRate = 1.0f / 8.0f; //!< rate at which the system reacts to load changes + uint8_t history = 15; //!< history size + uint8_t interval = 1; //!< desired frame interval in unit of 1.0 / DisplayInfo::refreshRate + }; + + /** + * ClearOptions are used at the beginning of a frame to clear or retain the SwapChain content. + */ + struct ClearOptions { + /** + * Color (sRGB linear) to use to clear the RenderTarget (typically the SwapChain). + * + * The RenderTarget is cleared using this color, which won't be tone-mapped since + * tone-mapping is part of View rendering (this is not). + * + * When a View is rendered, there are 3 scenarios to consider: + * - Pixels rendered by the View replace the clear color (or blend with it in + * `BlendMode::TRANSLUCENT` mode). + * + * - With blending mode set to `BlendMode::TRANSLUCENT`, Pixels untouched by the View + * are considered fulling transparent and let the clear color show through. + * + * - With blending mode set to `BlendMode::OPAQUE`, Pixels untouched by the View + * are set to the clear color. However, because it is now used in the context of a View, + * it will go through the post-processing stage, which includes tone-mapping. + * + * For consistency, it is recommended to always use a Skybox to clear an opaque View's + * background, or to use black or fully-transparent (i.e. {0,0,0,0}) as the clear color. + */ + math::float4 clearColor = {}; + + /** Value to clear the stencil buffer */ + uint8_t clearStencil = 0u; + + /** + * Whether the SwapChain should be cleared using the clearColor. Use this if translucent + * View will be drawn, for instance. + */ + bool clear = false; + + /** + * Whether the SwapChain content should be discarded. clear implies discard. Set this + * to false (along with clear to false as well) if the SwapChain already has content that + * needs to be preserved + */ + bool discard = true; + }; + + /** + * Information about the display this Renderer is associated to. This information is needed + * to accurately compute dynamic-resolution scaling and for frame-pacing. + */ + void setDisplayInfo(const DisplayInfo& info) noexcept; + + /** + * Set options controlling the desired frame-rate. + */ + void setFrameRateOptions(FrameRateOptions const& options) noexcept; + + /** + * Set ClearOptions which are used at the beginning of a frame to clear or retain the + * SwapChain content. + */ + void setClearOptions(const ClearOptions& options); + + /** + * Returns the ClearOptions currently set. + * @return A reference to a ClearOptions structure. + */ + ClearOptions const& getClearOptions() const noexcept; + + /** + * Get the Engine that created this Renderer. + * + * @return A pointer to the Engine instance this Renderer is associated to. + */ + Engine* UTILS_NONNULL getEngine() noexcept; + + /** + * Get the Engine that created this Renderer. + * + * @return A constant pointer to the Engine instance this Renderer is associated to. + */ + inline Engine const* UTILS_NONNULL getEngine() const noexcept { + return const_cast(this)->getEngine(); + } + + /** + * Flags used to configure the behavior of copyFrame(). + * + * @see + * copyFrame() + */ + using CopyFrameFlag = uint32_t; + + /** + * Indicates that the dstSwapChain passed into copyFrame() should be + * committed after the frame has been copied. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag COMMIT = 0x1; + /** + * Indicates that the presentation time should be set on the dstSwapChain + * passed into copyFrame to the monotonic clock time when the frame is + * copied. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag SET_PRESENTATION_TIME = 0x2; + /** + * Indicates that the dstSwapChain passed into copyFrame() should be + * cleared to black before the frame is copied into the specified viewport. + * + * @see + * copyFrame() + */ + static constexpr CopyFrameFlag CLEAR = 0x4; + + + /** + * Set-up a frame for this Renderer. + * + * beginFrame() manages frame pacing, and returns whether or not a frame should be drawn. The + * goal of this is to skip frames when the GPU falls behind in order to keep the frame + * latency low. + * + * If a given frame takes too much time in the GPU, the CPU will get ahead of the GPU. The + * display will draw the same frame twice producing a stutter. At this point, the CPU is + * ahead of the GPU and depending on how many frames are buffered, latency increases. + * + * beginFrame() attempts to detect this situation and returns false in that case, indicating + * to the caller to skip the current frame. + * + * When beginFrame() returns true, it is mandatory to render the frame and call endFrame(). + * However, when beginFrame() returns false, the caller has the choice to either skip the + * frame and not call endFrame(), or proceed as though true was returned. + * + * @param vsyncSteadyClockTimeNano The time in nanosecond of when the current frame started, + * or 0 if unknown. This value should be the timestamp of + * the last h/w vsync. It is expressed in the + * std::chrono::steady_clock time base. + * @param swapChain A pointer to the SwapChain instance to use. + * + * @return + * *false* the current frame should be skipped, + * *true* the current frame must be drawn and endFrame() must be called. + * + * @remark + * When skipping a frame, the whole frame is canceled, and endFrame() must not be called. + * + * @note + * All calls to render() must happen *after* beginFrame(). + * + * @see + * endFrame() + */ + bool beginFrame(SwapChain* UTILS_NONNULL swapChain, + uint64_t vsyncSteadyClockTimeNano = 0u); + + /** + * Set the time at which the frame must be presented to the display. + * + * This must be called between beginFrame() and endFrame(). + * + * @param monotonic_clock_ns the time in nanoseconds corresponding to the system monotonic up-time clock. + * the presentation time is typically set in the middle of the period + * of interest. The presentation time cannot be too far in the + * future because it is limited by how many buffers are available in + * the display sub-system. Typically it is set to 1 or 2 vsync periods + * away. + */ + void setPresentationTime(int64_t monotonic_clock_ns); + + /** + * Render a View into this renderer's window. + * + * This is filament main rendering method, most of the CPU-side heavy lifting is performed + * here. render() main function is to generate render commands which are asynchronously + * executed by the Engine's render thread. + * + * render() generates commands for each of the following stages: + * + * 1. Shadow map passes, if needed. + * 2. Depth pre-pass. + * 3. Color pass. + * 4. Post-processing pass. + * + * A typical render loop looks like this: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * void renderLoop(Renderer* renderer, SwapChain* swapChain) { + * do { + * // typically we wait for VSYNC and user input events + * if (renderer->beginFrame(swapChain)) { + * renderer->render(mView); + * renderer->endFrame(); + * } + * } while (!quit()); + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * + * @param view A pointer to the view to render. + * + * @attention + * render() must be called *after* beginFrame() and *before* endFrame(). + * + * @note + * render() must be called from the Engine's main thread (or external synchronization + * must be provided). In particular, calls to render() on different Renderer instances + * **must** be synchronized. + * + * @remark + * render() perform potentially heavy computations and cannot be multi-threaded. However, + * internally, render() is highly multi-threaded to both improve performance in mitigate + * the call's latency. + * + * @remark + * render() is typically called once per frame (but not necessarily). + * + * @see + * beginFrame(), endFrame(), View + * + */ + void render(View const* UTILS_NONNULL view); + + /** + * Copy the currently rendered view to the indicated swap chain, using the + * indicated source and destination rectangle. + * + * @param dstSwapChain The swap chain into which the frame should be copied. + * @param dstViewport The destination rectangle in which to draw the view. + * @param srcViewport The source rectangle to be copied. + * @param flags One or more CopyFrameFlag behavior configuration flags. + * + * @remark + * copyFrame() should be called after a frame is rendered using render() + * but before endFrame() is called. + */ + void copyFrame(SwapChain* UTILS_NONNULL dstSwapChain, Viewport const& dstViewport, + Viewport const& srcViewport, uint32_t flags = 0); + + /** + * Reads back the content of the SwapChain associated with this Renderer. + * + * @param xoffset Left offset of the sub-region to read back. + * @param yoffset Bottom offset of the sub-region to read back. + * @param width Width of the sub-region to read back. + * @param height Height of the sub-region to read back. + * @param buffer Client-side buffer where the read-back will be written. + * + * The following formats are always supported: + * - PixelBufferDescriptor::PixelDataFormat::RGBA + * - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER + * + * The following types are always supported: + * - PixelBufferDescriptor::PixelDataType::UBYTE + * - PixelBufferDescriptor::PixelDataType::UINT + * - PixelBufferDescriptor::PixelDataType::INT + * - PixelBufferDescriptor::PixelDataType::FLOAT + * + * Other combinations of format/type may be supported. If a combination is + * not supported, this operation may fail silently. Use a DEBUG build + * to get some logs about the failure. + * + * + * Framebuffer as seen on User buffer (PixelBufferDescriptor&) + * screen + * + * +--------------------+ + * | | .stride .alignment + * | | ----------------------->--> + * | | O----------------------+--+ low addresses + * | | | | | | + * | w | | | .top | | + * | <---------> | | V | | + * | +---------+ | | +---------+ | | + * | | ^ | | ======> | | | | | + * | x | h| | | |.left| | | | + * +------>| v | | +---->| | | | + * | +.........+ | | +.........+ | | + * | ^ | | | | + * | y | | +----------------------+--+ high addresses + * O------------+-------+ + * + * + * readPixels() must be called within a frame, meaning after beginFrame() and before endFrame(). + * Typically, readPixels() will be called after render(). + * + * After issuing this method, the callback associated with `buffer` will be invoked on the + * main thread, indicating that the read-back has completed. Typically, this will happen + * after multiple calls to beginFrame(), render(), endFrame(). + * + * It is also possible to use a Fence to wait for the read-back. + * + * @remark + * readPixels() is intended for debugging and testing. It will impact performance significantly. + * + */ + void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + backend::PixelBufferDescriptor&& buffer); + + /** + * Finishes the current frame and schedules it for display. + * + * endFrame() schedules the current frame to be displayed on the Renderer's window. + * + * @note + * All calls to render() must happen *before* endFrame(). endFrame() must be called if + * beginFrame() returned true, otherwise, endFrame() must not be called unless the caller + * ignored beginFrame()'s return value. + * + * @see + * beginFrame() + */ + void endFrame(); + + + /** + * Reads back the content of the provided RenderTarget. + * + * @param renderTarget RenderTarget to read back from. + * @param xoffset Left offset of the sub-region to read back. + * @param yoffset Bottom offset of the sub-region to read back. + * @param width Width of the sub-region to read back. + * @param height Height of the sub-region to read back. + * @param buffer Client-side buffer where the read-back will be written. + * + * The following formats are always supported: + * - PixelBufferDescriptor::PixelDataFormat::RGBA + * - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER + * + * The following types are always supported: + * - PixelBufferDescriptor::PixelDataType::UBYTE + * - PixelBufferDescriptor::PixelDataType::UINT + * - PixelBufferDescriptor::PixelDataType::INT + * - PixelBufferDescriptor::PixelDataType::FLOAT + * + * Other combinations of format/type may be supported. If a combination is + * not supported, this operation may fail silently. Use a DEBUG build + * to get some logs about the failure. + * + * + * Framebuffer as seen on User buffer (PixelBufferDescriptor&) + * screen + * + * +--------------------+ + * | | .stride .alignment + * | | ----------------------->--> + * | | O----------------------+--+ low addresses + * | | | | | | + * | w | | | .top | | + * | <---------> | | V | | + * | +---------+ | | +---------+ | | + * | | ^ | | ======> | | | | | + * | x | h| | | |.left| | | | + * +------>| v | | +---->| | | | + * | +.........+ | | +.........+ | | + * | ^ | | | | + * | y | | +----------------------+--+ high addresses + * O------------+-------+ + * + * + * Typically readPixels() will be called after render() and before endFrame(). + * + * After issuing this method, the callback associated with `buffer` will be invoked on the + * main thread, indicating that the read-back has completed. Typically, this will happen + * after multiple calls to beginFrame(), render(), endFrame(). + * + * It is also possible to use a Fence to wait for the read-back. + * + * OpenGL only: if issuing a readPixels on a RenderTarget backed by a Texture that had data + * uploaded to it via setImage, the data returned from readPixels will be y-flipped with respect + * to the setImage call. + * + * @remark + * readPixels() is intended for debugging and testing. It will impact performance significantly. + * + */ + void readPixels(RenderTarget* UTILS_NONNULL renderTarget, + uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + backend::PixelBufferDescriptor&& buffer); + + /** + * Render a standalone View into its associated RenderTarget + * + * This call is mostly equivalent to calling render(View*) inside a + * beginFrame / endFrame block, but incurs less overhead. It can be used + * as a poor man's compute API. + * + * @param view A pointer to the view to render. This View must have a RenderTarget associated + * to it. + * + * @attention + * renderStandaloneView() must be called outside of beginFrame() / endFrame(). + * + * @note + * renderStandaloneView() must be called from the Engine's main thread + * (or external synchronization must be provided). In particular, calls to + * renderStandaloneView() on different Renderer instances **must** be synchronized. + * + * @remark + * renderStandaloneView() perform potentially heavy computations and cannot be multi-threaded. + * However, internally, renderStandaloneView() is highly multi-threaded to both improve + * performance in mitigate the call's latency. + */ + void renderStandaloneView(View const* UTILS_NONNULL view); + + + /** + * Returns the time in second of the last call to beginFrame(). This value is constant for all + * views rendered during a frame. The epoch is set with resetUserTime(). + * + * In materials, this value can be queried using `vec4 getUserTime()`. The value returned + * is a highp vec4 encoded as follows: + * + * time.x = (float)Renderer.getUserTime(); + * time.y = Renderer.getUserTime() - time.x; + * + * It follows that the following invariants are true: + * + * (double)time.x + (double)time.y == Renderer.getUserTime() + * time.x == (float)Renderer.getUserTime() + * + * This encoding allows the shader code to perform high precision (i.e. double) time + * calculations when needed despite the lack of double precision in the shader, for e.g.: + * + * To compute (double)time * vertex in the material, use the following construct: + * + * vec3 result = time.x * vertex + time.y * vertex; + * + * + * Most of the time, high precision computations are not required, but be aware that the + * precision of time.x rapidly diminishes as time passes: + * + * time | precision + * --------+---------- + * 16.7s | us + * 4h39 | ms + * 77h | 1/60s + * + * + * In other words, it only possible to get microsecond accuracy for about 16s or millisecond + * accuracy for just under 5h. + * + * This problem can be mitigated by calling resetUserTime(), or using high precision time as + * described above. + * + * @return The time is seconds since resetUserTime() was last called. + * + * @see + * resetUserTime() + */ + double getUserTime() const; + + /** + * Sets the user time epoch to now, i.e. resets the user time to zero. + * + * Use this method used to keep the precision of time high in materials, in practice it should + * be called at least when the application is paused, e.g. Activity.onPause() in Android. + * + * @see + * getUserTime() + */ + void resetUserTime(); + +protected: + // prevent heap allocation + ~Renderer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_RENDERER_H diff --git a/package/ios/libs/filament/include/filament/Scene.h b/package/ios/libs/filament/include/filament/Scene.h new file mode 100644 index 00000000..9df6285c --- /dev/null +++ b/package/ios/libs/filament/include/filament/Scene.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_SCENE_H +#define TNT_FILAMENT_SCENE_H + +#include + +#include +#include + +#include + +namespace utils { + class Entity; +} // namespace utils + +namespace filament { + +class IndirectLight; +class Skybox; + +/** + * A Scene is a flat container of Renderable and Light instances. + * + * A Scene doesn't provide a hierarchy of Renderable objects, i.e.: it's not a scene-graph. + * However, it manages the list of objects to render and the list of lights. Renderable + * and Light objects can be added or removed from a Scene at any time. + * + * A Renderable *must* be added to a Scene in order to be rendered, and the Scene must be + * provided to a View. + * + * + * Creation and Destruction + * ======================== + * + * A Scene is created using Engine.createScene() and destroyed using + * Engine.destroy(const Scene*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * #include + * using namespace filament; + * + * Engine* engine = Engine::create(); + * + * Scene* scene = engine->createScene(); + * engine->destroy(&scene); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see View, Renderable, Light + */ +class UTILS_PUBLIC Scene : public FilamentAPI { +public: + + /** + * Sets the Skybox. + * + * The Skybox is drawn last and covers all pixels not touched by geometry. + * + * @param skybox The Skybox to use to fill untouched pixels, or nullptr to unset the Skybox. + */ + void setSkybox(Skybox* UTILS_NULLABLE skybox) noexcept; + + /** + * Returns the Skybox associated with the Scene. + * + * @return The associated Skybox, or nullptr if there is none. + */ + Skybox* UTILS_NULLABLE getSkybox() const noexcept; + + /** + * Set the IndirectLight to use when rendering the Scene. + * + * Currently, a Scene may only have a single IndirectLight. This call replaces the current + * IndirectLight. + * + * @param ibl The IndirectLight to use when rendering the Scene or nullptr to unset. + * @see getIndirectLight + */ + void setIndirectLight(IndirectLight* UTILS_NULLABLE ibl) noexcept; + + /** + * Get the IndirectLight or nullptr if none is set. + * + * @return the the IndirectLight or nullptr if none is set + * @see setIndirectLight + */ + IndirectLight* UTILS_NULLABLE getIndirectLight() const noexcept; + + /** + * Adds an Entity to the Scene. + * + * @param entity The entity is ignored if it doesn't have a Renderable or Light component. + * + * \attention + * A given Entity object can only be added once to a Scene. + * + */ + void addEntity(utils::Entity entity); + + /** + * Adds a list of entities to the Scene. + * + * @param entities Array containing entities to add to the scene. + * @param count Size of the entity array. + */ + void addEntities(const utils::Entity* UTILS_NONNULL entities, size_t count); + + /** + * Removes the Renderable from the Scene. + * + * @param entity The Entity to remove from the Scene. If the specified + * \p entity doesn't exist, this call is ignored. + */ + void remove(utils::Entity entity); + + /** + * Removes a list of entities to the Scene. + * + * This is equivalent to calling remove in a loop. + * If any of the specified entities do not exist in the scene, they are skipped. + * + * @param entities Array containing entities to remove from the scene. + * @param count Size of the entity array. + */ + void removeEntities(const utils::Entity* UTILS_NONNULL entities, size_t count); + + /** + * Returns the total number of Entities in the Scene, whether alive or not. + * @return Total number of Entities in the Scene. + */ + size_t getEntityCount() const noexcept; + + /** + * Returns the number of active (alive) Renderable objects in the Scene. + * + * @return The number of active (alive) Renderable objects in the Scene. + */ + size_t getRenderableCount() const noexcept; + + /** + * Returns the number of active (alive) Light objects in the Scene. + * + * @return The number of active (alive) Light objects in the Scene. + */ + size_t getLightCount() const noexcept; + + /** + * Returns true if the given entity is in the Scene. + * + * @return Whether the given entity is in the Scene. + */ + bool hasEntity(utils::Entity entity) const noexcept; + + /** + * Invokes user functor on each entity in the scene. + * + * It is not allowed to add or remove an entity from the scene within the functor. + * + * @param functor User provided functor called for each entity in the scene + */ + void forEach(utils::Invocable&& functor) const noexcept; + +protected: + // prevent heap allocation + ~Scene() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SCENE_H diff --git a/package/ios/libs/filament/include/filament/SkinningBuffer.h b/package/ios/libs/filament/include/filament/SkinningBuffer.h new file mode 100644 index 00000000..36ae30ed --- /dev/null +++ b/package/ios/libs/filament/include/filament/SkinningBuffer.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_SKINNINGBUFFER_H +#define TNT_FILAMENT_SKINNINGBUFFER_H + +#include + +#include + +#include + +#include + +#include +#include + +namespace filament { + +/** + * SkinningBuffer is used to hold skinning data (bones). It is a simple wraper around + * a structured UBO. + * @see RenderableManager::setSkinningBuffer + */ +class UTILS_PUBLIC SkinningBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Size of the skinning buffer in bones. + * + * Due to limitation in the GLSL, the SkinningBuffer must always by a multiple of + * 256, this adjustment is done automatically, but can cause + * some memory overhead. This memory overhead can be mitigated by using the same + * SkinningBuffer to store the bone information for multiple RenderPrimitives. + * + * @param boneCount Number of bones the skinning buffer can hold. + * @return A reference to this Builder for chaining calls. + */ + Builder& boneCount(uint32_t boneCount) noexcept; + + /** + * The new buffer is created with identity bones + * @param initialize true to initializing the buffer, false to not. + * @return A reference to this Builder for chaining calls. + */ + Builder& initialize(bool initialize = true) noexcept; + + /** + * Creates the SkinningBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + * + * @see SkinningBuffer::setBones + */ + SkinningBuffer* UTILS_NONNULL build(Engine& engine); + private: + friend class FSkinningBuffer; + }; + + /** + * Updates the bone transforms in the range [offset, offset + count). + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * @param transforms pointer to at least count Bone + * @param count number of Bone elements in transforms + * @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms) + * @see RenderableManager::setSkinningBuffer + */ + void setBones(Engine& engine, RenderableManager::Bone const* UTILS_NONNULL transforms, + size_t count, size_t offset = 0); + + /** + * Updates the bone transforms in the range [offset, offset + count). + * @param engine Reference to the filament::Engine to associate this SkinningBuffer with. + * @param transforms pointer to at least count mat4f + * @param count number of mat4f elements in transforms + * @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms) + * @see RenderableManager::setSkinningBuffer + */ + void setBones(Engine& engine, math::mat4f const* UTILS_NONNULL transforms, + size_t count, size_t offset = 0); + + /** + * Returns the size of this SkinningBuffer in elements. + * @return The number of bones the SkinningBuffer holds. + */ + size_t getBoneCount() const noexcept; + +protected: + // prevent heap allocation + ~SkinningBuffer() = default; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_SKINNINGBUFFER_H diff --git a/package/ios/libs/filament/include/filament/Skybox.h b/package/ios/libs/filament/include/filament/Skybox.h new file mode 100644 index 00000000..ce203aae --- /dev/null +++ b/package/ios/libs/filament/include/filament/Skybox.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2016 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_SKYBOX_H +#define TNT_FILAMENT_SKYBOX_H + +#include + +#include + +#include + +#include + +namespace filament { + +class FSkybox; + +class Engine; +class Texture; + +/** + * Skybox + * + * When added to a Scene, the Skybox fills all untouched pixels. + * + * Creation and destruction + * ======================== + * + * A Skybox object is created using the Skybox::Builder and destroyed by calling + * Engine::destroy(const Skybox*). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::IndirectLight* skybox = filament::Skybox::Builder() + * .environment(cubemap) + * .build(*engine); + * + * engine->destroy(skybox); + * ~~~~~~~~~~~ + * + * + * @note + * Currently only Texture based sky boxes are supported. + * + * @see Scene, IndirectLight + */ +class UTILS_PUBLIC Skybox : public FilamentAPI { + struct BuilderDetails; + +public: + //! Use Builder to construct an Skybox object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Set the environment map (i.e. the skybox content). + * + * The Skybox is rendered as though it were an infinitely large cube with the camera + * inside it. This means that the cubemap which is mapped onto the cube's exterior + * will appear mirrored. This follows the OpenGL conventions. + * + * The cmgen tool generates reflection maps by default which are therefore ideal to use + * as skyboxes. + * + * @param cubemap This Texture must be a cube map. + * + * @return This Builder, for chaining calls. + * + * @see Texture + */ + Builder& environment(Texture* UTILS_NONNULL cubemap) noexcept; + + /** + * Indicates whether the sun should be rendered. The sun can only be + * rendered if there is at least one light of type SUN in the scene. + * The default value is false. + * + * @param show True if the sun should be rendered, false otherwise + * + * @return This Builder, for chaining calls. + */ + Builder& showSun(bool show) noexcept; + + /** + * Skybox intensity when no IndirectLight is set on the Scene. + * + * This call is ignored when an IndirectLight is set on the Scene, and the intensity + * of the IndirectLight is used instead. + * + * @param envIntensity Scale factor applied to the skybox texel values such that + * the result is in lux, or lumen/m^2 (default = 30000) + * + * @return This Builder, for chaining calls. + * + * @see IndirectLight::Builder::intensity + */ + Builder& intensity(float envIntensity) noexcept; + + /** + * Sets the skybox to a constant color. Default is opaque black. + * + * Ignored if an environment is set. + * + * @param color the constant color + * + * @return This Builder, for chaining calls. + */ + Builder& color(math::float4 color) noexcept; + + /** + * Creates the Skybox object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Skybox with. + * + * @return pointer to the newly created object. + */ + Skybox* UTILS_NONNULL build(Engine& engine); + + private: + friend class FSkybox; + }; + + void setColor(math::float4 color) noexcept; + + /** + * Sets bits in a visibility mask. By default, this is 0x1. + * + * This provides a simple mechanism for hiding or showing this Skybox in a Scene. + * + * @see View::setVisibleLayers(). + * + * For example, to set bit 1 and reset bits 0 and 2 while leaving all other bits unaffected, + * call: `setLayerMask(7, 2)`. + * + * @param select the set of bits to affect + * @param values the replacement values for the affected bits + */ + void setLayerMask(uint8_t select, uint8_t values) noexcept; + + /** + * @return the visibility mask bits + */ + uint8_t getLayerMask() const noexcept; + + /** + * Returns the skybox's intensity in lux, or lumen/m^2. + */ + float getIntensity() const noexcept; + + /** + * @return the associated texture + */ + Texture const* UTILS_NONNULL getTexture() const noexcept; + +protected: + // prevent heap allocation + ~Skybox() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SKYBOX_H diff --git a/package/ios/libs/filament/include/filament/Stream.h b/package/ios/libs/filament/include/filament/Stream.h new file mode 100644 index 00000000..6cafbacc --- /dev/null +++ b/package/ios/libs/filament/include/filament/Stream.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_STREAM_H +#define TNT_FILAMENT_STREAM_H + +#include + +#include +#include + +#include + +#include + +namespace filament { + +class FStream; + +class Engine; + +/** + * Stream is used to attach a video stream to a Filament `Texture`. + * + * Note that the `Stream` class is fairly Android centric. It supports two different + * configurations: + * + * - ACQUIRED.....connects to an Android AHardwareBuffer + * - NATIVE.......connects to an Android SurfaceTexture + * + * Before explaining these different configurations, let's review the high-level structure of an AR + * or video application that uses Filament: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * while (true) { + * + * // Misc application work occurs here, such as: + * // - Writing the image data for a video frame into a Stream + * // - Moving the Filament Camera + * + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Let's say that the video image data at the time of a particular invocation of `beginFrame` + * becomes visible to users at time A. The 3D scene state (including the camera) at the time of + * that same invocation becomes apparent to users at time B. + * + * - If time A matches time B, we say that the stream is \em{synchronized}. + * - Filament invokes low-level graphics commands on the \em{driver thread}. + * - The thread that calls `beginFrame` is called the \em{main thread}. + * + * For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires + * the stream, then releases it later via a callback function. This configuration is especially + * useful when the Vulkan backend is enabled. + * + * For NATIVE streams, Filament does not make any synchronization guarantee. However they are simple + * to use and do not incur a copy. These are often appropriate in video applications. + * + * Please see `sample-stream-test` and `sample-hello-camera` for usage examples. + * + * @see backend::StreamType + * @see Texture#setExternalStream + * @see Engine#destroyStream + */ +class UTILS_PUBLIC Stream : public FilamentAPI { + struct BuilderDetails; + +public: + using Callback = backend::StreamCallback; + using StreamType = backend::StreamType; + + /** + * Constructs a Stream object instance. + * + * By default, Stream objects are ACQUIRED and must have external images pushed to them via + *
Stream::setAcquiredImage
. + * + * To create a NATIVE stream, call the
stream
method on the builder. + */ + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Creates a NATIVE stream. Native streams can sample data directly from an + * opaque platform object such as a SurfaceTexture on Android. + * + * @param stream An opaque native stream handle. e.g.: on Android this is an + * `android/graphics/SurfaceTexture` JNI jobject. The wrap mode must + * be CLAMP_TO_EDGE. + * + * @return This Builder, for chaining calls. + */ + Builder& stream(void* UTILS_NULLABLE stream) noexcept; + + /** + * + * @param width initial width of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @return This Builder, for chaining calls. + */ + Builder& width(uint32_t width) noexcept; + + /** + * + * @param height initial height of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @return This Builder, for chaining calls. + */ + Builder& height(uint32_t height) noexcept; + + /** + * Creates the Stream object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Stream with. + * + * @return pointer to the newly created object. + */ + Stream* UTILS_NONNULL build(Engine& engine); + + private: + friend class FStream; + }; + + /** + * Indicates whether this stream is a NATIVE stream or ACQUIRED stream. + */ + StreamType getStreamType() const noexcept; + + /** + * Updates an ACQUIRED stream with an image that is guaranteed to be used in the next frame. + * + * This method tells Filament to immediately "acquire" the image and trigger a callback + * when it is done with it. This should be called by the user outside of beginFrame / endFrame, + * and should be called only once per frame. If the user pushes images to the same stream + * multiple times in a single frame, only the final image is honored, but all callbacks are + * invoked. + * + * This method should be called on the same thread that calls Renderer::beginFrame, which is + * also where the callback is invoked. This method can only be used for streams that were + * constructed without calling the `stream` method on the builder. + * + * @see Stream for more information about NATIVE and ACQUIRED configurations. + * + * @param image Pointer to AHardwareBuffer, casted to void* since this is a public header. + * @param callback This is triggered by Filament when it wishes to release the image. + * The callback tales two arguments: the AHardwareBuffer and the userdata. + * @param userdata Optional closure data. Filament will pass this into the callback when it + * releases the image. + */ + void setAcquiredImage(void* UTILS_NONNULL image, + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + + /** + * @see setAcquiredImage(void*, Callback, void*) + * + * @param image Pointer to AHardwareBuffer, casted to void* since this is a public header. + * @param handler Handler to dispatch the AcquiredImage or nullptr for the default handler. + * @param callback This is triggered by Filament when it wishes to release the image. + * It callback tales two arguments: the AHardwareBuffer and the userdata. + * @param userdata Optional closure data. Filament will pass this into the callback when it + * releases the image. + */ + void setAcquiredImage(void* UTILS_NONNULL image, + backend::CallbackHandler* UTILS_NULLABLE handler, + Callback UTILS_NONNULL callback, void* UTILS_NULLABLE userdata) noexcept; + + /** + * Updates the size of the incoming stream. Whether this value is used is + * stream dependent. On Android, it must be set when using + * Builder::stream(long externalTextureId). + * + * @param width new width of the incoming stream + * @param height new height of the incoming stream + */ + void setDimensions(uint32_t width, uint32_t height) noexcept; + + /** + * Returns the presentation time of the currently displayed frame in nanosecond. + * + * This value can change at any time. + * + * @return timestamp in nanosecond. + */ + int64_t getTimestamp() const noexcept; + +protected: + // prevent heap allocation + ~Stream() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_STREAM_H diff --git a/package/ios/libs/filament/include/filament/SwapChain.h b/package/ios/libs/filament/include/filament/SwapChain.h new file mode 100644 index 00000000..8db477ad --- /dev/null +++ b/package/ios/libs/filament/include/filament/SwapChain.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_SWAPCHAIN_H +#define TNT_FILAMENT_SWAPCHAIN_H + +#include + +#include +#include + +#include +#include + +#include + +namespace filament { + +class Engine; + +/** + * A swap chain represents an Operating System's *native* renderable surface. + * + * Typically it's a native window or a view. Because a SwapChain is initialized from a + * native object, it is given to filament as a `void *`, which must be of the proper type + * for each platform filament is running on. + * + * \code + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * \endcode + * + * When Engine::create() is used without specifying a Platform, the `nativeWindow` + * parameter above must be of type: + * + * Platform | nativeWindow type + * :---------------|:----------------------------: + * Android | ANativeWindow* + * macOS - OpenGL | NSView* + * macOS - Metal | CAMetalLayer* + * iOS - OpenGL | CAEAGLLayer* + * iOS - Metal | CAMetalLayer* + * X11 | Window + * Windows | HWND + * + * Otherwise, the `nativeWindow` is defined by the concrete implementation of Platform. + * + * + * Examples: + * + * Android + * ------- + * + * On Android, an `ANativeWindow*` can be obtained from a Java `Surface` object using: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * #include + * // parameters + * // env: JNIEnv* + * // surface: jobject + * ANativeWindow* win = ANativeWindow_fromSurface(env, surface); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * \warning + * Don't use reflection to access the `mNativeObject` field, it won't work. + * + * A `Surface` can be retrieved from a `SurfaceView` or `SurfaceHolder` easily using + * `SurfaceHolder.getSurface()` and/or `SurfaceView.getHolder()`. + * + * \note + * To use a `TextureView` as a SwapChain, it is necessary to first get its `SurfaceTexture`, + * for instance using `TextureView.SurfaceTextureListener` and then create a `Surface`: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java} + * // using a TextureView.SurfaceTextureListener: + * public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { + * mSurface = new Surface(surfaceTexture); + * // mSurface can now be used in JNI to create an ANativeWindow. + * } + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Linux + * ----- + * + * Example using SDL: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * SDL_GetWindowWMInfo(sdlWindow, &wmi); + * Window nativeWindow = (Window) wmi.info.x11.window; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Windows + * ------- + * + * Example using SDL: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * ASSERT_POSTCONDITION(SDL_GetWindowWMInfo(sdlWindow, &wmi), "SDL version unsupported!"); + * HDC nativeWindow = (HDC) wmi.info.win.hdc; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * OSX + * --- + * + * On OSX, any `NSView` can be used *directly* as a `nativeWindow` with createSwapChain(). + * + * Example using SDL/Objective-C: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.mm} + * #include + * + * #include + * #include + * + * SDL_SysWMinfo wmi; + * SDL_VERSION(&wmi.version); + * NSWindow* win = (NSWindow*) wmi.info.cocoa.window; + * NSView* view = [win contentView]; + * void* nativeWindow = view; + * + * using namespace filament; + * Engine* engine = Engine::create(); + * SwapChain* swapChain = engine->createSwapChain(nativeWindow); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @see Engine + */ +class UTILS_PUBLIC SwapChain : public FilamentAPI { +public: + using FrameScheduledCallback = backend::FrameScheduledCallback; + using FrameCompletedCallback = utils::Invocable; + + /** + * Requests a SwapChain with an alpha channel. + */ + static const uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT; + + /** + * This flag indicates that the swap chain may be used as a source surface + * for reading back render results. This config must be set when creating + * any swap chain that will be used as the source for a blit operation. + * + * @see + * Renderer.copyFrame() + */ + static const uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE; + + /** + * Indicates that the native X11 window is an XCB window rather than an XLIB window. + * This is ignored on non-Linux platforms and in builds that support only one X11 API. + */ + static const uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB; + + /** + * Indicates that the native window is a CVPixelBufferRef. + * + * This is only supported by the Metal backend. The CVPixelBuffer must be in the + * kCVPixelFormatType_32BGRA format. + * + * It is not necessary to add an additional retain call before passing the pixel buffer to + * Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and + * CVPixelBufferRelease when the swap chain is destroyed. + */ + static const uint64_t CONFIG_APPLE_CVPIXELBUFFER = + backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER; + + /** + * Indicates that the SwapChain must automatically perform linear to sRGB encoding. + * + * This flag is ignored if isSRGBSwapChainSupported() is false. + * + * When using this flag, the output colorspace in ColorGrading should be set to + * Rec709-Linear-D65, or post-processing should be disabled. + * + * @see isSRGBSwapChainSupported() + * @see ColorGrading.outputColorSpace() + * @see View.setPostProcessingEnabled() + */ + static constexpr uint64_t CONFIG_SRGB_COLORSPACE = backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE; + + /** + * Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer. + * + * This flag is necessary when using View::setStencilBufferEnabled and rendering directly into + * the SwapChain (when post-processing is disabled). + * + * The specific format of the stencil buffer depends on platform support. The following pixel + * formats are tried, in order of preference: + * + * Depth only (without CONFIG_HAS_STENCIL_BUFFER): + * - DEPTH32F + * - DEPTH24 + * + * Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER): + * - DEPTH32F_STENCIL8 + * - DEPTH24F_STENCIL8 + * + * Note that enabling the stencil buffer may hinder depth precision and should only be used if + * necessary. + * + * @see View.setStencilBufferEnabled + * @see View.setPostProcessingEnabled + */ + static constexpr uint64_t CONFIG_HAS_STENCIL_BUFFER = backend::SWAP_CHAIN_HAS_STENCIL_BUFFER; + + /** + * Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag. + * The default implementation returns false. + * + * @param engine A pointer to the filament Engine + * @return true if SWAP_CHAIN_CONFIG_SRGB_COLORSPACE is supported, false otherwise. + */ + static bool isSRGBSwapChainSupported(Engine& engine) noexcept; + + void* UTILS_NULLABLE getNativeWindow() const noexcept; + + /** + * FrameScheduledCallback is a callback function that notifies an application when Filament has + * completed processing a frame and that frame is ready to be scheduled for presentation. + * + * Typically, Filament is responsible for scheduling the frame's presentation to the SwapChain. + * If a SwapChain::FrameScheduledCallback is set, however, the application bares the + * responsibility of scheduling a frame for presentation by calling the backend::PresentCallable + * passed to the callback function. Currently this functionality is only supported by the Metal + * backend. + * + * A FrameScheduledCallback can be set on an individual SwapChain through + * SwapChain::setFrameScheduledCallback. If the callback is set, then the SwapChain will *not* + * automatically schedule itself for presentation. Instead, the application must call the + * PresentCallable passed to the FrameScheduledCallback. + * + * If your application delays the call to the PresentCallable by, for example, calling it on a + * separate thread, you must ensure all PresentCallables have been called before shutting down + * the Filament Engine. You can do this by issuing an Engine::flushAndWait before calling + * Engine::shutdown. This is necessary to ensure the Filament Engine has had a chance to clean + * up all memory related to frame presentation. + * + * @param callback A callback, or nullptr to unset. + * @param user An optional pointer to user data passed to the callback function. + * + * @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other + * backends ignore the callback (which will never be called) and proceed normally. + * + * @remark The SwapChain::FrameScheduledCallback is called on an arbitrary thread. + * + * @see PresentCallable + */ + void setFrameScheduledCallback(FrameScheduledCallback UTILS_NULLABLE callback, + void* UTILS_NULLABLE user = nullptr); + + /** + * FrameCompletedCallback is a callback function that notifies an application when a frame's + * contents have completed rendering on the GPU. + * + * Use SwapChain::setFrameCompletedCallback to set a callback on an individual SwapChain. Each + * time a frame completes GPU rendering, the callback will be called. + * + * If handler is nullptr, the callback is guaranteed to be called on the main Filament thread. + * + * Use \c setFrameCompletedCallback() (with default arguments) to unset the callback. + * + * @param handler Handler to dispatch the callback or nullptr for the default handler. + * @param callback Callback called when each frame completes. + * + * @remark Only Filament's Metal backend supports frame callbacks. Other backends ignore the + * callback (which will never be called) and proceed normally. + * + * @see CallbackHandler + */ + void setFrameCompletedCallback(backend::CallbackHandler* UTILS_NULLABLE handler = nullptr, + FrameCompletedCallback&& callback = {}) noexcept; + + +protected: + // prevent heap allocation + ~SwapChain() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_SWAPCHAIN_H diff --git a/package/ios/libs/filament/include/filament/Texture.h b/package/ios/libs/filament/include/filament/Texture.h new file mode 100644 index 00000000..1b7c39ea --- /dev/null +++ b/package/ios/libs/filament/include/filament/Texture.h @@ -0,0 +1,556 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_TEXTURE_H +#define TNT_FILAMENT_TEXTURE_H + +#include + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +class FTexture; + +class Engine; +class Stream; + +/** + * Texture + * + * The Texture class supports: + * - 2D textures + * - 3D textures + * - Cube maps + * - mip mapping + * + * + * Creation and destruction + * ======================== + * + * A Texture object is created using the Texture::Builder and destroyed by calling + * Engine::destroy(const Texture*). + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * + * filament::Texture* texture = filament::Texture::Builder() + * .width(64) + * .height(64) + * .build(*engine); + * + * engine->destroy(texture); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +class UTILS_PUBLIC Texture : public FilamentAPI { + struct BuilderDetails; + +public: + static constexpr const size_t BASE_LEVEL = 0; + + //! Face offsets for all faces of a cubemap + struct FaceOffsets; + + using PixelBufferDescriptor = backend::PixelBufferDescriptor; //!< Geometry of a pixel buffer + using Sampler = backend::SamplerType; //!< Type of sampler + using InternalFormat = backend::TextureFormat; //!< Internal texel format + using CubemapFace = backend::TextureCubemapFace; //!< Cube map faces + using Format = backend::PixelDataFormat; //!< Pixel color format + using Type = backend::PixelDataType; //!< Pixel data format + using CompressedType = backend::CompressedPixelDataType; //!< Compressed pixel data format + using Usage = backend::TextureUsage; //!< Usage affects texel layout + using Swizzle = backend::TextureSwizzle; //!< Texture swizzle + + /** @return whether a backend supports a particular format. */ + static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept; + + /** @return whether a backend supports texture swizzling. */ + static bool isTextureSwizzleSupported(Engine& engine) noexcept; + + static size_t computeTextureDataSize(Texture::Format format, Texture::Type type, + size_t stride, size_t height, size_t alignment) noexcept; + + + /** + * Options for environment prefiltering into reflection map + * + * @see generatePrefilterMipmap() + */ + struct PrefilterOptions { + uint16_t sampleCount = 8; //!< sample count used for filtering + bool mirror = true; //!< whether the environment must be mirrored + private: + UTILS_UNUSED uintptr_t reserved[3] = {}; + }; + + + //! Use Builder to construct a Texture object instance + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Specifies the width in texels of the texture. Doesn't need to be a power-of-two. + * @param width Width of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + */ + Builder& width(uint32_t width) noexcept; + + /** + * Specifies the height in texels of the texture. Doesn't need to be a power-of-two. + * @param height Height of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + */ + Builder& height(uint32_t height) noexcept; + + /** + * Specifies the depth in texels of the texture. Doesn't need to be a power-of-two. + * The depth controls the number of layers in a 2D array texture. Values greater than 1 + * effectively create a 3D texture. + * @param depth Depth of the texture in texels (default: 1). + * @return This Builder, for chaining calls. + * @attention This Texture instance must use Sampler::SAMPLER_3D or + * Sampler::SAMPLER_2D_ARRAY or it has no effect. + */ + Builder& depth(uint32_t depth) noexcept; + + /** + * Specifies the numbers of mip map levels. + * This creates a mip-map pyramid. The maximum number of levels a texture can have is + * such that max(width, height, level) / 2^MAX_LEVELS = 1 + * @param levels Number of mipmap levels for this texture. + * @return This Builder, for chaining calls. + */ + Builder& levels(uint8_t levels) noexcept; + + /** + * Specifies the type of sampler to use. + * @param target Sampler type + * @return This Builder, for chaining calls. + * @see Sampler + */ + Builder& sampler(Sampler target) noexcept; + + /** + * Specifies the *internal* format of this texture. + * + * The internal format specifies how texels are stored (which may be different from how + * they're specified in setImage()). InternalFormat specifies both the color components + * and the data type used. + * + * @param format Format of the texture's texel. + * @return This Builder, for chaining calls. + * @see InternalFormat, setImage + */ + Builder& format(InternalFormat format) noexcept; + + /** + * Specifies if the texture will be used as a render target attachment. + * + * If the texture is potentially rendered into, it may require a different memory layout, + * which needs to be known during construction. + * + * @param usage Defaults to Texture::Usage::DEFAULT; c.f. Texture::Usage::COLOR_ATTACHMENT. + * @return This Builder, for chaining calls. + */ + Builder& usage(Usage usage) noexcept; + + /** + * Specifies how a texture's channels map to color components + * + * Texture Swizzle is only supported if isTextureSwizzleSupported() returns true. + * + * @param r texture channel for red component + * @param g texture channel for green component + * @param b texture channel for blue component + * @param a texture channel for alpha component + * @return This Builder, for chaining calls. + * @see Texture::isTextureSwizzleSupported() + */ + Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept; + + /** + * Creates the Texture object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this Texture with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + Texture* UTILS_NONNULL build(Engine& engine); + + /* no user serviceable parts below */ + + /** + * Specify a native texture to import as a Filament texture. + * + * The texture id is backend-specific: + * - OpenGL: GLuint texture ID + * - Metal: id + * + * With Metal, the id object should be cast to an intptr_t using + * CFBridgingRetain to transfer ownership to Filament. Filament will release ownership of + * the texture object when the Filament texture is destroyed. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + * id metalTexture = ... + * filamentTexture->import((intptr_t) CFBridgingRetain(metalTexture)); + * // free to release metalTexture + * + * // after using texture: + * engine->destroy(filamentTexture); // metalTexture is released + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @warning This method should be used as a last resort. This API is subject to change or + * removal. + * + * @param id a backend specific texture identifier + * + * @return This Builder, for chaining calls. + */ + Builder& import(intptr_t id) noexcept; + + private: + friend class FTexture; + }; + + /** + * Returns the width of a 2D or 3D texture level + * @param level texture level. + * @return Width in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getWidth(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the height of a 2D or 3D texture level + * @param level texture level. + * @return Height in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getHeight(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the depth of a 3D texture level + * @param level texture level. + * @return Depth in texel of the specified \p level, clamped to 1. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getDepth(size_t level = BASE_LEVEL) const noexcept; + + /** + * Returns the maximum number of levels this texture can have. + * @return maximum number of levels this texture can have. + * @attention If this texture is using Sampler::SAMPLER_EXTERNAL, the dimension + * of the texture are unknown and this method always returns whatever was set on the Builder. + */ + size_t getLevels() const noexcept; + + /** + * Return this texture Sampler as set by Builder::sampler(). + * @return this texture Sampler as set by Builder::sampler() + */ + Sampler getTarget() const noexcept; + + /** + * Return this texture InternalFormat as set by Builder::format(). + * @return this texture InternalFormat as set by Builder::format(). + */ + InternalFormat getFormat() const noexcept; + + /** + * Updates a sub-image of a 3D texture or 2D texture array for a level. Cubemaps are treated + * like a 2D array of six layers. + * + * @param engine Engine this texture is associated to. + * @param level Level to set the image for. + * @param xoffset Left offset of the sub-region to update. + * @param yoffset Bottom offset of the sub-region to update. + * @param zoffset Depth offset of the sub-region to update. + * @param width Width of the sub-region to update. + * @param height Height of the sub-region to update. + * @param depth Depth of the sub-region to update. + * @param buffer Client-side buffer containing the image to set. + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention \p level must be less than getLevels(). + * @attention \p buffer's Texture::Format must match that of getFormat(). + * @attention This Texture instance must use Sampler::SAMPLER_3D, Sampler::SAMPLER_2D_ARRAY + * or Sampler::SAMPLER_CUBEMAP. + * + * @see Builder::sampler() + */ + void setImage(Engine& engine, size_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + uint32_t width, uint32_t height, uint32_t depth, + PixelBufferDescriptor&& buffer) const; + + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { + setImage(engine, level, 0, 0, 0, + uint32_t(getWidth(level)), uint32_t(getHeight(level)), 1, std::move(buffer)); + } + + /** + * inline helper to update a 2D texture + * + * @see setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + inline void setImage(Engine& engine, size_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, + PixelBufferDescriptor&& buffer) const { + setImage(engine, level, xoffset, yoffset, 0, width, height, 1, std::move(buffer)); + } + + /** + * Specify all six images of a cube map level. + * + * This method follows exactly the OpenGL conventions. + * + * @param engine Engine this texture is associated to. + * @param level Level to set the image for. + * @param buffer Client-side buffer containing the images to set. + * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets + * are specified in the following order: +x, -x, +y, -y, +z, -z + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention \p level must be less than getLevels(). + * @attention \p buffer's Texture::Format must match that of getFormat(). + * @attention This Texture instance must use Sampler::SAMPLER_CUBEMAP or it has no effect + * + * @see Texture::CubemapFace, Builder::sampler() + * + * @deprecated Instead, use setImage(Engine& engine, size_t level, + * uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + * uint32_t width, uint32_t height, uint32_t depth, + * PixelBufferDescriptor&& buffer) + */ + UTILS_DEPRECATED + void setImage(Engine& engine, size_t level, + PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; + + + /** + * Specify the external image to associate with this Texture. Typically the external + * image is OS specific, and can be a video or camera frame. + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. Supported types are + * eglImageOES on Android and CVPixelBufferRef on iOS. + * + * On iOS the following pixel formats are supported: + * - kCVPixelFormatType_32BGRA + * - kCVPixelFormatType_420YpCbCr8BiPlanarFullRange + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * + * @see Builder::sampler() + * + */ + void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; + + /** + * Specify the external image and plane to associate with this Texture. Typically the external + * image is OS specific, and can be a video or camera frame. When using this method, the + * external image must be a planar type (such as a YUV camera frame). The plane parameter + * selects which image plane is bound to this texture. + * + * A single external image can be bound to different Filament textures, with each texture + * associated with a separate plane: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * textureA->setExternalImage(engine, image, 0); + * textureB->setExternalImage(engine, image, 1); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. Supported types are + * eglImageOES on Android and CVPixelBufferRef on iOS. + * @param plane The plane index of the external image to associate with this texture. + * + * This method is only meaningful on iOS with + * kCVPixelFormatType_420YpCbCr8BiPlanarFullRange images. On platforms + * other than iOS, this method is a no-op. + */ + void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane) noexcept; + + /** + * Specify the external stream to associate with this Texture. Typically the external + * stream is OS specific, and can be a video or camera stream. + * There are many restrictions when using an external stream as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external stream + * + * @param engine Engine this texture is associated to. + * @param stream A Stream object + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * + * @see Builder::sampler(), Stream + * + */ + void setExternalStream(Engine& engine, Stream* UTILS_NULLABLE stream) noexcept; + + /** + * Generates all the mipmap levels automatically. This requires the texture to have a + * color-renderable format and usage set to BLIT_SRC | BLIT_DST. If unspecified, + * usage bits are set automatically. + * + * @param engine Engine this texture is associated to. + * + * @attention \p engine must be the instance passed to Builder::build() + * @attention This Texture instance must NOT use SamplerType::SAMPLER_3D or it has no effect + */ + void generateMipmaps(Engine& engine) const noexcept; + + /** + * Creates a reflection map from an environment map. + * + * This is a utility function that replaces calls to Texture::setImage(). + * The provided environment map is processed and all mipmap levels are populated. The + * processing is similar to the offline tool `cmgen` as a lower quality setting. + * + * This function is intended to be used when the environment cannot be processed offline, + * for instance if it's generated at runtime. + * + * The source data must obey to some constraints: + * - the data type must be PixelDataFormat::RGB + * - the data format must be one of + * - PixelDataType::FLOAT + * - PixelDataType::HALF + * + * The current texture must be a cubemap + * + * The reflections cubemap's internal format cannot be a compressed format. + * + * The reflections cubemap's dimension must be a power-of-two. + * + * @warning This operation is computationally intensive, especially with large environments and + * is currently synchronous. Expect about 1ms for a 16x16 cubemap. + * + * @param engine Reference to the filament::Engine to associate this IndirectLight with. + * @param buffer Client-side buffer containing the images to set. + * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets + * are specified in the following order: +x, -x, +y, -y, +z, -z + * @param options Optional parameter to controlling user-specified quality and options. + * + * @exception utils::PreConditionPanic if the source data constraints are not respected. + * + */ + void generatePrefilterMipmap(Engine& engine, + PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, + PrefilterOptions const* UTILS_NULLABLE options = nullptr); + + + /** @deprecated */ + struct FaceOffsets { + using size_type = size_t; + union { + struct { + size_type px; //!< +x face offset in bytes + size_type nx; //!< -x face offset in bytes + size_type py; //!< +y face offset in bytes + size_type ny; //!< -y face offset in bytes + size_type pz; //!< +z face offset in bytes + size_type nz; //!< -z face offset in bytes + }; + size_type offsets[6]; + }; + size_type operator[](size_t n) const noexcept { return offsets[n]; } + size_type& operator[](size_t n) { return offsets[n]; } + FaceOffsets() noexcept = default; + explicit FaceOffsets(size_type faceSize) noexcept { + px = faceSize * 0; + nx = faceSize * 1; + py = faceSize * 2; + ny = faceSize * 3; + pz = faceSize * 4; + nz = faceSize * 5; + } + FaceOffsets(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + } + FaceOffsets& operator=(const FaceOffsets& rhs) noexcept { + px = rhs.px; + nx = rhs.nx; + py = rhs.py; + ny = rhs.ny; + pz = rhs.pz; + nz = rhs.nz; + return *this; + } + }; + +protected: + // prevent heap allocation + ~Texture() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TEXTURE_H diff --git a/package/ios/libs/filament/include/filament/TextureSampler.h b/package/ios/libs/filament/include/filament/TextureSampler.h new file mode 100644 index 00000000..ba5e5534 --- /dev/null +++ b/package/ios/libs/filament/include/filament/TextureSampler.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_TEXTURESAMPLER_H +#define TNT_FILAMENT_TEXTURESAMPLER_H + +#include + +#include + +#include + +#include + +namespace filament { + +/** + * TextureSampler defines how a texture is accessed. + */ +class UTILS_PUBLIC TextureSampler { +public: + using WrapMode = backend::SamplerWrapMode; + using MinFilter = backend::SamplerMinFilter; + using MagFilter = backend::SamplerMagFilter; + using CompareMode = backend::SamplerCompareMode; + using CompareFunc = backend::SamplerCompareFunc; + + /** + * Creates a default sampler. + * The default parameters are: + * - filterMag : NEAREST + * - filterMin : NEAREST + * - wrapS : CLAMP_TO_EDGE + * - wrapT : CLAMP_TO_EDGE + * - wrapR : CLAMP_TO_EDGE + * - compareMode : NONE + * - compareFunc : Less or equal + * - no anisotropic filtering + */ + TextureSampler() noexcept = default; + + explicit TextureSampler(backend::SamplerParams params) noexcept : mSamplerParams(params) { } + + TextureSampler(const TextureSampler& rhs) noexcept = default; + TextureSampler& operator=(const TextureSampler& rhs) noexcept = default; + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param minMag filtering for both minification and magnification + * @param str wrapping mode for all texture coordinate axes + */ + explicit TextureSampler(MagFilter minMag, WrapMode str = WrapMode::CLAMP_TO_EDGE) noexcept { + mSamplerParams.filterMin = MinFilter(minMag); + mSamplerParams.filterMag = minMag; + mSamplerParams.wrapS = str; + mSamplerParams.wrapT = str; + mSamplerParams.wrapR = str; + } + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param min filtering for minification + * @param mag filtering for magnification + * @param str wrapping mode for all texture coordinate axes + */ + TextureSampler(MinFilter min, MagFilter mag, WrapMode str = WrapMode::CLAMP_TO_EDGE) noexcept { + mSamplerParams.filterMin = min; + mSamplerParams.filterMag = mag; + mSamplerParams.wrapS = str; + mSamplerParams.wrapT = str; + mSamplerParams.wrapR = str; + } + + /** + * Creates a TextureSampler with the default parameters but setting the filtering and wrap modes. + * @param min filtering for minification + * @param mag filtering for magnification + * @param s wrap mode for the s (horizontal)texture coordinate + * @param t wrap mode for the t (vertical) texture coordinate + * @param r wrap mode for the r (depth) texture coordinate + */ + TextureSampler(MinFilter min, MagFilter mag, WrapMode s, WrapMode t, WrapMode r) noexcept { + mSamplerParams.filterMin = min; + mSamplerParams.filterMag = mag; + mSamplerParams.wrapS = s; + mSamplerParams.wrapT = t; + mSamplerParams.wrapR = r; + } + + /** + * Creates a TextureSampler with the default parameters but setting the compare mode and function + * @param mode Compare mode + * @param func Compare function + */ + explicit TextureSampler(CompareMode mode, CompareFunc func = CompareFunc::LE) noexcept { + mSamplerParams.compareMode = mode; + mSamplerParams.compareFunc = func; + } + + /** + * Sets the minification filter + * @param v Minification filter + */ + void setMinFilter(MinFilter v) noexcept { + mSamplerParams.filterMin = v; + } + + /** + * Sets the magnification filter + * @param v Magnification filter + */ + void setMagFilter(MagFilter v) noexcept { + mSamplerParams.filterMag = v; + } + + /** + * Sets the wrap mode for the s (horizontal) texture coordinate + * @param v wrap mode + */ + void setWrapModeS(WrapMode v) noexcept { + mSamplerParams.wrapS = v; + } + + /** + * Sets the wrap mode for the t (vertical) texture coordinate + * @param v wrap mode + */ + void setWrapModeT(WrapMode v) noexcept { + mSamplerParams.wrapT = v; + } + + /** + * Sets the wrap mode for the r (depth, for 3D textures) texture coordinate + * @param v wrap mode + */ + void setWrapModeR(WrapMode v) noexcept { + mSamplerParams.wrapR = v; + } + + /** + * This controls anisotropic filtering. + * @param anisotropy Amount of anisotropy, should be a power-of-two. The default is 0. + * The maximum permissible value is 7. + */ + void setAnisotropy(float anisotropy) noexcept { + const int log2 = ilogbf(anisotropy > 0 ? anisotropy : -anisotropy); + mSamplerParams.anisotropyLog2 = uint8_t(log2 < 7 ? log2 : 7); + } + + /** + * Sets the compare mode and function. + * @param mode Compare mode + * @param func Compare function + */ + void setCompareMode(CompareMode mode, CompareFunc func = CompareFunc::LE) noexcept { + mSamplerParams.compareMode = mode; + mSamplerParams.compareFunc = func; + } + + //! returns the minification filter value + MinFilter getMinFilter() const noexcept { return mSamplerParams.filterMin; } + + //! returns the magnification filter value + MagFilter getMagFilter() const noexcept { return mSamplerParams.filterMag; } + + //! returns the s-coordinate wrap mode (horizontal) + WrapMode getWrapModeS() const noexcept { return mSamplerParams.wrapS; } + + //! returns the t-coordinate wrap mode (vertical) + WrapMode getWrapModeT() const noexcept { return mSamplerParams.wrapT; } + + //! returns the r-coordinate wrap mode (depth) + WrapMode getWrapModeR() const noexcept { return mSamplerParams.wrapR; } + + //! returns the anisotropy value + float getAnisotropy() const noexcept { return float(1u << mSamplerParams.anisotropyLog2); } + + //! returns the compare mode + CompareMode getCompareMode() const noexcept { return mSamplerParams.compareMode; } + + //! returns the compare function + CompareFunc getCompareFunc() const noexcept { return mSamplerParams.compareFunc; } + + + // no user-serviceable parts below... + backend::SamplerParams getSamplerParams() const noexcept { return mSamplerParams; } + +private: + backend::SamplerParams mSamplerParams{}; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TEXTURESAMPLER_H diff --git a/package/ios/libs/filament/include/filament/ToneMapper.h b/package/ios/libs/filament/include/filament/ToneMapper.h new file mode 100644 index 00000000..74e26614 --- /dev/null +++ b/package/ios/libs/filament/include/filament/ToneMapper.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef TNT_FILAMENT_TONEMAPPER_H +#define TNT_FILAMENT_TONEMAPPER_H + +#include + +#include + +#include + +namespace filament { + +/** + * Interface for tone mapping operators. A tone mapping operator, or tone mapper, + * is responsible for compressing the dynamic range of the rendered scene to a + * dynamic range suitable for display. + * + * In Filament, tone mapping is a color grading step. ToneMapper instances are + * created and passed to the ColorGrading::Builder to produce a 3D LUT that will + * be used during post-processing to prepare the final color buffer for display. + * + * Filament provides several default tone mapping operators that fall into three + * categories: + * + * - Configurable tone mapping operators + * - GenericToneMapper + * - Fixed-aesthetic tone mapping operators + * - ACESToneMapper + * - ACESLegacyToneMapper + * - FilmicToneMapper + * - Debug/validation tone mapping operators + * - LinearToneMapper + * - DisplayRangeToneMapper + * + * You can create custom tone mapping operators by subclassing ToneMapper. + */ +struct UTILS_PUBLIC ToneMapper { + ToneMapper() noexcept; + virtual ~ToneMapper() noexcept; + + /** + * Maps an open domain (or "scene referred" values) color value to display + * domain (or "display referred") color value. Both the input and output + * color values are defined in the Rec.2020 color space, with no transfer + * function applied ("linear Rec.2020"). + * + * @param c Input color to tone map, in the Rec.2020 color space with no + * transfer function applied ("linear") + * + * @return A tone mapped color in the Rec.2020 color space, with no transfer + * function applied ("linear") + */ + virtual math::float3 operator()(math::float3 c) const noexcept = 0; +}; + +/** + * Linear tone mapping operator that returns the input color but clamped to + * the 0..1 range. This operator is mostly useful for debugging. + */ +struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper { + LinearToneMapper() noexcept; + ~LinearToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * ACES tone mapping operator. This operator is an implementation of the + * ACES Reference Rendering Transform (RRT) combined with the Output Device + * Transform (ODT) for sRGB monitors (dim surround, 100 nits). + */ +struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper { + ACESToneMapper() noexcept; + ~ACESToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * ACES tone mapping operator, modified to match the perceived brightness + * of FilmicToneMapper. This operator is the same as ACESToneMapper but + * applies a brightness multiplier of ~1.6 to the input color value to + * target brighter viewing environments. + */ +struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper { + ACESLegacyToneMapper() noexcept; + ~ACESLegacyToneMapper() noexcept final; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +/** + * "Filmic" tone mapping operator. This tone mapper was designed to + * approximate the aesthetics of the ACES RRT + ODT for Rec.709 + * and historically Filament's default tone mapping operator. It exists + * only for backward compatibility purposes and is not otherwise recommended. + */ +struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper { + FilmicToneMapper() noexcept; + ~FilmicToneMapper() noexcept final; + + math::float3 operator()(math::float3 x) const noexcept override; +}; + +/** + * AgX tone mapping operator. + */ +struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper { + + enum class AgxLook : uint8_t { + NONE = 0, //!< Base contrast with no look applied + PUNCHY, //!< A punchy and more chroma laden look for sRGB displays + GOLDEN //!< A golden tinted, slightly washed look for BT.1886 displays + }; + + /** + * Builds a new AgX tone mapper. + * + * @param look an optional creative adjustment to contrast and saturation + */ + explicit AgxToneMapper(AgxLook look = AgxLook::NONE) noexcept; + ~AgxToneMapper() noexcept final; + + math::float3 operator()(math::float3 x) const noexcept override; + + AgxLook look; +}; + +/** + * Generic tone mapping operator that gives control over the tone mapping + * curve. This operator can be used to control the aesthetics of the final + * image. This operator also allows to control the dynamic range of the + * scene referred values. + * + * The tone mapping curve is defined by 5 parameters: + * - contrast: controls the contrast of the curve + * - midGrayIn: sets the input middle gray + * - midGrayOut: sets the output middle gray + * - hdrMax: defines the maximum input value that will be mapped to + * output white + */ +struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper { + /** + * Builds a new generic tone mapper. The default values of the + * constructor parameters approximate an ACES tone mapping curve + * and the maximum input value is set to 10.0. + * + * @param contrast controls the contrast of the curve, must be > 0.0, values + * in the range 0.5..2.0 are recommended. + * @param midGrayIn sets the input middle gray, between 0.0 and 1.0. + * @param midGrayOut sets the output middle gray, between 0.0 and 1.0. + * @param hdrMax defines the maximum input value that will be mapped to + * output white. Must be >= 1.0. + */ + explicit GenericToneMapper( + float contrast = 1.55f, + float midGrayIn = 0.18f, + float midGrayOut = 0.215f, + float hdrMax = 10.0f + ) noexcept; + ~GenericToneMapper() noexcept final; + + GenericToneMapper(GenericToneMapper const&) = delete; + GenericToneMapper& operator=(GenericToneMapper const&) = delete; + GenericToneMapper(GenericToneMapper&& rhs) noexcept; + GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept; + + math::float3 operator()(math::float3 x) const noexcept override; + + /** Returns the contrast of the curve as a strictly positive value. */ + float getContrast() const noexcept; + + /** Returns how fast scene referred values map to output white as a value between 0.0 and 1.0. */ + float getShoulder() const noexcept; + + /** Returns the middle gray point for input values as a value between 0.0 and 1.0. */ + float getMidGrayIn() const noexcept; + + /** Returns the middle gray point for output values as a value between 0.0 and 1.0. */ + float getMidGrayOut() const noexcept; + + /** Returns the maximum input value that will map to output white, as a value >= 1.0. */ + float getHdrMax() const noexcept; + + /** Sets the contrast of the curve, must be > 0.0, values in the range 0.5..2.0 are recommended. */ + void setContrast(float contrast) noexcept; + + /** Sets the input middle gray, between 0.0 and 1.0. */ + void setMidGrayIn(float midGrayIn) noexcept; + + /** Sets the output middle gray, between 0.0 and 1.0. */ + void setMidGrayOut(float midGrayOut) noexcept; + + /** Defines the maximum input value that will be mapped to output white. Must be >= 1.0. */ + void setHdrMax(float hdrMax) noexcept; + +private: + struct Options; + Options* mOptions; +}; + +/** + * A tone mapper that converts the input HDR RGB color into one of 16 debug colors + * that represent the pixel's exposure. When the output is cyan, the input color + * represents middle gray (18% exposure). Every exposure stop above or below middle + * gray causes a color shift. + * + * The relationship between exposures and colors is: + * + * - -5EV black + * - -4EV darkest blue + * - -3EV darker blue + * - -2EV dark blue + * - -1EV blue + * - OEV cyan + * - +1EV dark green + * - +2EV green + * - +3EV yellow + * - +4EV yellow-orange + * - +5EV orange + * - +6EV bright red + * - +7EV red + * - +8EV magenta + * - +9EV purple + * - +10EV white + * + * This tone mapper is useful to validate and tweak scene lighting. + */ +struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper { + DisplayRangeToneMapper() noexcept; + ~DisplayRangeToneMapper() noexcept override; + + math::float3 operator()(math::float3 c) const noexcept override; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_TONEMAPPER_H diff --git a/package/ios/libs/filament/include/filament/TransformManager.h b/package/ios/libs/filament/include/filament/TransformManager.h new file mode 100644 index 00000000..5d612a16 --- /dev/null +++ b/package/ios/libs/filament/include/filament/TransformManager.h @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_FILAMENT_TRANSFORMMANAGER_H +#define TNT_FILAMENT_TRANSFORMMANAGER_H + +#include + +#include +#include + +#include + +#include + +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament { + +class FTransformManager; + +/** + * TransformManager is used to add transform components to entities. + * + * A Transform component gives an entity a position and orientation in space in the coordinate + * space of its parent transform. The TransformManager takes care of computing the world-space + * transform of each component (i.e. its transform relative to the root). + * + * Creation and destruction + * ======================== + * + * A transform component is created using TransformManager::create() and destroyed by calling + * TransformManager::destroy(). + * + * ~~~~~~~~~~~{.cpp} + * filament::Engine* engine = filament::Engine::create(); + * utils::Entity object = utils::EntityManager.get().create(); + * + * auto& tcm = engine->getTransformManager(); + * + * // create the transform component + * tcm.create(object); + * + * // set its transform + * auto i = tcm.getInstance(object); + * tcm.setTransform(i, mat4f::translation({ 0, 0, -1 })); + * + * // destroy the transform component + * tcm.destroy(object); + * ~~~~~~~~~~~ + * + */ +class UTILS_PUBLIC TransformManager : public FilamentAPI { +public: + using Instance = utils::EntityInstance; + + class children_iterator { + friend class FTransformManager; + TransformManager const& mManager; + Instance mInstance; + children_iterator(TransformManager const& mgr, Instance instance) noexcept + : mManager(mgr), mInstance(instance) { } + public: + using value_type = Instance; + using difference_type = ptrdiff_t; + using pointer = Instance*; + using reference = Instance&; + using iterator_category = std::forward_iterator_tag; + + children_iterator& operator++(); + + children_iterator operator++(int) { // NOLINT + children_iterator ret(*this); + ++(*this); + return ret; + } + + bool operator == (const children_iterator& other) const noexcept { + return mInstance == other.mInstance; + } + + bool operator != (const children_iterator& other) const noexcept { + return mInstance != other.mInstance; + } + + value_type operator*() const { return mInstance; } + }; + + /** + * Returns whether a particular Entity is associated with a component of this TransformManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(utils::Entity e) const noexcept; + + /** + * Gets an Instance representing the transform component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the transform component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(utils::Entity e) const noexcept; + + /** + * @return the number of Components + */ + size_t getComponentCount() const noexcept; + + /** + * @return true if the this manager has no components + */ + bool empty() const noexcept; + + /** + * Retrieve the `Entity` of the component from its `Instance`. + * @param i Instance of the component obtained from getInstance() + * @return + */ + utils::Entity getEntity(Instance i) const noexcept; + + /** + * Retrieve the Entities of all the components of this manager. + * @return A list, in no particular order, of all the entities managed by this manager. + */ + utils::Entity const* UTILS_NONNULL getEntities() const noexcept; + + /** + * Enables or disable the accurate translation mode. Disabled by default. + * + * When accurate translation mode is active, the translation component of all transforms is + * maintained at double precision. This is only useful if the mat4 version of setTransform() + * is used, as well as getTransformAccurate(). + * + * @param enable true to enable the accurate translation mode, false to disable. + * + * @see isAccurateTranslationsEnabled + * @see create(utils::Entity, Instance, const math::mat4&); + * @see setTransform(Instance, const math::mat4&) + * @see getTransformAccurate + * @see getWorldTransformAccurate + */ + void setAccurateTranslationsEnabled(bool enable) noexcept; + + /** + * Returns whether the high precision translation mode is active. + * @return true if accurate translations mode is active, false otherwise + * @see setAccurateTranslationsEnabled + */ + bool isAccurateTranslationsEnabled() const noexcept; + + /** + * Creates a transform component and associate it with the given entity. + * @param entity An Entity to associate a transform component to. + * @param parent The Instance of the parent transform, or Instance{} if no parent. + * @param localTransform The transform to initialize the transform component with. + * This is always relative to the parent. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(utils::Entity e) was called. + * + * @see destroy() + */ + void create(utils::Entity entity, Instance parent, const math::mat4f& localTransform); + void create(utils::Entity entity, Instance parent, const math::mat4& localTransform); //!< \overload + void create(utils::Entity entity, Instance parent = {}); //!< \overload + + /** + * Destroys this component from the given entity, children are orphaned. + * @param e An entity. + * + * @note If this transform had children, these are orphaned, which means their local + * transform becomes a world transform. Usually it's nonsensical. It's recommended to make + * sure that a destroyed transform doesn't have children. + * + * @see create() + */ + void destroy(utils::Entity e) noexcept; + + /** + * Re-parents an entity to a new one. + * @param i The instance of the transform component to re-parent + * @param newParent The instance of the new parent transform + * @attention It is an error to re-parent an entity to a descendant and will cause undefined behaviour. + * @see getInstance() + */ + void setParent(Instance i, Instance newParent) noexcept; + + /** + * Returns the parent of a transform component, or the null entity if it is a root. + * @param i The instance of the transform component to query. + */ + utils::Entity getParent(Instance i) const noexcept; + + /** + * Returns the number of children of a transform component. + * @param i The instance of the transform component to query. + * @return The number of children of the queried component. + */ + size_t getChildCount(Instance i) const noexcept; + + /** + * Gets a list of children for a transform component. + * + * @param i The instance of the transform component to query. + * @param children Pointer to array-of-Entity. The array must have at least "count" elements. + * @param count The maximum number of children to retrieve. + * @return The number of children written to the pointer. + */ + size_t getChildren(Instance i, utils::Entity* UTILS_NONNULL children, size_t count) const noexcept; + + /** + * Returns an iterator to the Instance of the first child of the given parent. + * + * @param parent Instance of the parent + * @return A forward iterator pointing to the first child of the given parent. + * + * A child_iterator can only safely be dereferenced if it's different from getChildrenEnd(parent) + */ + children_iterator getChildrenBegin(Instance parent) const noexcept; + + /** + * Returns an undreferencable iterator representing the end of the children list + * + * @param parent Instance of the parent + * @return A forward iterator. + * + * This iterator cannot be dereferenced + */ + children_iterator getChildrenEnd(Instance parent) const noexcept; + + /** + * Sets a local transform of a transform component. + * @param ci The instance of the transform component to set the local transform to. + * @param localTransform The local transform (i.e. relative to the parent). + * @see getTransform() + * @attention This operation can be slow if the hierarchy of transform is too deep, and this + * will be particularly bad when updating a lot of transforms. In that case, + * consider using openLocalTransformTransaction() / commitLocalTransformTransaction(). + */ + void setTransform(Instance ci, const math::mat4f& localTransform) noexcept; + + /** + * Sets a local transform of a transform component and keeps double precision translation. + * All other values of the transform are stored at single precision. + * @param ci The instance of the transform component to set the local transform to. + * @param localTransform The local transform (i.e. relative to the parent). + * @see getTransform() + * @attention This operation can be slow if the hierarchy of transform is too deep, and this + * will be particularly bad when updating a lot of transforms. In that case, + * consider using openLocalTransformTransaction() / commitLocalTransformTransaction(). + */ + void setTransform(Instance ci, const math::mat4& localTransform) noexcept; + + /** + * Returns the local transform of a transform component. + * @param ci The instance of the transform component to query the local transform from. + * @return The local transform of the component (i.e. relative to the parent). This always + * returns the value set by setTransform(). + * @see setTransform() + */ + const math::mat4f& getTransform(Instance ci) const noexcept; + + /** + * Returns the local transform of a transform component. + * @param ci The instance of the transform component to query the local transform from. + * @return The local transform of the component (i.e. relative to the parent). This always + * returns the value set by setTransform(). + * @see setTransform() + */ + math::mat4 getTransformAccurate(Instance ci) const noexcept; + + /** + * Return the world transform of a transform component. + * @param ci The instance of the transform component to query the world transform from. + * @return The world transform of the component (i.e. relative to the root). This is the + * composition of this component's local transform with its parent's world transform. + * @see setTransform() + */ + const math::mat4f& getWorldTransform(Instance ci) const noexcept; + + /** + * Return the world transform of a transform component. + * @param ci The instance of the transform component to query the world transform from. + * @return The world transform of the component (i.e. relative to the root). This is the + * composition of this component's local transform with its parent's world transform. + * @see setTransform() + */ + math::mat4 getWorldTransformAccurate(Instance ci) const noexcept; + + /** + * Opens a local transform transaction. During a transaction, getWorldTransform() can + * return an invalid transform until commitLocalTransformTransaction() is called. However, + * setTransform() will perform significantly better and in constant time. + * + * This is useful when updating many transforms and the transform hierarchy is deep (say more + * than 4 or 5 levels). + * + * @note If the local transform transaction is already open, this is a no-op. + * + * @see commitLocalTransformTransaction(), setTransform() + */ + void openLocalTransformTransaction() noexcept; + + /** + * Commits the currently open local transform transaction. When this returns, calls + * to getWorldTransform() will return the proper value. + * + * @attention failing to call this method when done updating the local transform will cause + * a lot of rendering problems. The system never closes the transaction + * automatically. + * + * @note If the local transform transaction is not open, this is a no-op. + * + * @see openLocalTransformTransaction(), setTransform() + */ + void commitLocalTransformTransaction() noexcept; + +protected: + // prevent heap allocation + ~TransformManager() = default; +}; + +} // namespace filament + + +#endif // TNT_TRANSFORMMANAGER_H diff --git a/package/ios/libs/filament/include/filament/VertexBuffer.h b/package/ios/libs/filament/include/filament/VertexBuffer.h new file mode 100644 index 00000000..fccbd004 --- /dev/null +++ b/package/ios/libs/filament/include/filament/VertexBuffer.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VERTEXBUFFER_H +#define TNT_FILAMENT_VERTEXBUFFER_H + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace filament { + +class FVertexBuffer; + +class BufferObject; +class Engine; + +/** + * Holds a set of buffers that define the geometry of a Renderable. + * + * The geometry of the Renderable itself is defined by a set of vertex attributes such as + * position, color, normals, tangents, etc... + * + * There is no need to have a 1-to-1 mapping between attributes and buffer. A buffer can hold the + * data of several attributes -- attributes are then referred as being "interleaved". + * + * The buffers themselves are GPU resources, therefore mutating their data can be relatively slow. + * For this reason, it is best to separate the constant data from the dynamic data into multiple + * buffers. + * + * It is possible, and even encouraged, to use a single vertex buffer for several Renderables. + * + * @see IndexBuffer, RenderableManager + */ +class UTILS_PUBLIC VertexBuffer : public FilamentAPI { + struct BuilderDetails; + +public: + using AttributeType = backend::ElementType; + using BufferDescriptor = backend::BufferDescriptor; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + /** + * Defines how many buffers will be created in this vertex buffer set. These buffers are + * later referenced by index from 0 to \p bufferCount - 1. + * + * This call is mandatory. The default is 0. + * + * @param bufferCount Number of buffers in this vertex buffer set. The maximum value is 8. + * @return A reference to this Builder for chaining calls. + */ + Builder& bufferCount(uint8_t bufferCount) noexcept; + + /** + * Size of each buffer in the set in vertex. + * + * @param vertexCount Number of vertices in each buffer in this set. + * @return A reference to this Builder for chaining calls. + */ + Builder& vertexCount(uint32_t vertexCount) noexcept; + + /** + * Allows buffers to be swapped out and shared using BufferObject. + * + * If buffer objects mode is enabled, clients must call setBufferObjectAt rather than + * setBufferAt. This allows sharing of data between VertexBuffer objects, but it may + * slightly increase the memory footprint of Filament's internal bookkeeping. + * + * @param enabled If true, enables buffer object mode. False by default. + */ + Builder& enableBufferObjects(bool enabled = true) noexcept; + + /** + * Sets up an attribute for this vertex buffer set. + * + * Using \p byteOffset and \p byteStride, attributes can be interleaved in the same buffer. + * + * @param attribute The attribute to set up. + * @param bufferIndex The index of the buffer containing the data for this attribute. Must + * be between 0 and bufferCount() - 1. + * @param attributeType The type of the attribute data (e.g. byte, float3, etc...) + * @param byteOffset Offset in *bytes* into the buffer \p bufferIndex + * @param byteStride Stride in *bytes* to the next element of this attribute. When set to + * zero the attribute size, as defined by \p attributeType is used. + * + * @return A reference to this Builder for chaining calls. + * + * @warning VertexAttribute::TANGENTS must be specified as a quaternion and is how normals + * are specified. + * + * @warning Not all backends support 3-component attributes that are not floats. For help + * with conversion, see geometry::Transcoder. + * + * @see VertexAttribute + * + * This is a no-op if the \p attribute is an invalid enum. + * This is a no-op if the \p bufferIndex is out of bounds. + * + */ + Builder& attribute(VertexAttribute attribute, uint8_t bufferIndex, + AttributeType attributeType, + uint32_t byteOffset = 0, uint8_t byteStride = 0) noexcept; + + /** + * Sets whether a given attribute should be normalized. By default attributes are not + * normalized. A normalized attribute is mapped between 0 and 1 in the shader. This applies + * only to integer types. + * + * @param attribute Enum of the attribute to set the normalization flag to. + * @param normalize true to automatically normalize the given attribute. + * @return A reference to this Builder for chaining calls. + * + * This is a no-op if the \p attribute is an invalid enum. + */ + Builder& normalized(VertexAttribute attribute, bool normalize = true) noexcept; + + /** + * Sets advanced skinning mode. Bone data, indices and weights will be + * set in RenderableManager:Builder:boneIndicesAndWeights methods. + * Works with or without buffer objects. + * + * @param enabled If true, enables advanced skinning mode. False by default. + * + * @return A reference to this Builder for chaining calls. + * + * @see RenderableManager:Builder:boneIndicesAndWeights + */ + Builder& advancedSkinning(bool enabled) noexcept; + + /** + * Creates the VertexBuffer object and returns a pointer to it. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * + * @return pointer to the newly created object. + * + * @exception utils::PostConditionPanic if a runtime error occurred, such as running out of + * memory or other resources. + * @exception utils::PreConditionPanic if a parameter to a builder function was invalid. + */ + VertexBuffer* UTILS_NONNULL build(Engine& engine); + + private: + friend class FVertexBuffer; + }; + + /** + * Returns the vertex count. + * @return Number of vertices in this vertex buffer set. + */ + size_t getVertexCount() const noexcept; + + /** + * Asynchronously copy-initializes the specified buffer from the given buffer data. + * + * Do not use this if you called enableBufferObjects() on the Builder. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * @param bufferIndex Index of the buffer to initialize. Must be between 0 + * and Builder::bufferCount() - 1. + * @param buffer A BufferDescriptor representing the data used to initialize the buffer at + * index \p bufferIndex. BufferDescriptor points to raw, untyped data that will + * be copied as-is into the buffer. + * @param byteOffset Offset in *bytes* into the buffer at index \p bufferIndex of this vertex + * buffer set. + */ + void setBufferAt(Engine& engine, uint8_t bufferIndex, BufferDescriptor&& buffer, + uint32_t byteOffset = 0); + + /** + * Swaps in the given buffer object. + * + * To use this, you must first call enableBufferObjects() on the Builder. + * + * @param engine Reference to the filament::Engine to associate this VertexBuffer with. + * @param bufferIndex Index of the buffer to initialize. Must be between 0 + * and Builder::bufferCount() - 1. + * @param bufferObject The handle to the GPU data that will be used in this buffer slot. + */ + void setBufferObjectAt(Engine& engine, uint8_t bufferIndex, + BufferObject const* UTILS_NONNULL bufferObject); + +protected: + // prevent heap allocation + ~VertexBuffer() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VERTEXBUFFER_H diff --git a/package/ios/libs/filament/include/filament/View.h b/package/ios/libs/filament/include/filament/View.h new file mode 100644 index 00000000..3cdd527f --- /dev/null +++ b/package/ios/libs/filament/include/filament/View.h @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VIEW_H +#define TNT_FILAMENT_VIEW_H + +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +namespace filament { + +namespace backend { +class CallbackHandler; +} // namespace backend + +class Camera; +class ColorGrading; +class MaterialInstance; +class RenderTarget; +class Scene; +class Viewport; + +/** + * A View encompasses all the state needed for rendering a Scene. + * + * Renderer::render() operates on View objects. These View objects specify important parameters + * such as: + * - The Scene + * - The Camera + * - The Viewport + * - Some rendering parameters + * + * \note + * View instances are heavy objects that internally cache a lot of data needed for rendering. + * It is not advised for an application to use many View objects. + * + * For example, in a game, a View could be used for the main scene and another one for the + * game's user interface. More View instances could be used for creating special effects (e.g. + * a View is akin to a rendering pass). + * + * + * @see Renderer, Scene, Camera, RenderTarget + */ +class UTILS_PUBLIC View : public FilamentAPI { +public: + using QualityLevel = filament::QualityLevel; + using BlendMode = filament::BlendMode; + using AntiAliasing = filament::AntiAliasing; + using Dithering = filament::Dithering; + using ShadowType = filament::ShadowType; + + using DynamicResolutionOptions = filament::DynamicResolutionOptions; + using BloomOptions = filament::BloomOptions; + using FogOptions = filament::FogOptions; + using DepthOfFieldOptions = filament::DepthOfFieldOptions; + using VignetteOptions = filament::VignetteOptions; + using RenderQuality = filament::RenderQuality; + using AmbientOcclusionOptions = filament::AmbientOcclusionOptions; + using TemporalAntiAliasingOptions = filament::TemporalAntiAliasingOptions; + using MultiSampleAntiAliasingOptions = filament::MultiSampleAntiAliasingOptions; + using VsmShadowOptions = filament::VsmShadowOptions; + using SoftShadowOptions = filament::SoftShadowOptions; + using ScreenSpaceReflectionsOptions = filament::ScreenSpaceReflectionsOptions; + using GuardBandOptions = filament::GuardBandOptions; + using StereoscopicOptions = filament::StereoscopicOptions; + + /** + * Sets the View's name. Only useful for debugging. + * @param name Pointer to the View's name. The string is copied. + */ + void setName(const char* UTILS_NONNULL name) noexcept; + + /** + * Returns the View's name + * + * @return a pointer owned by the View instance to the View's name. + * + * @attention Do *not* free the pointer or modify its content. + */ + const char* UTILS_NULLABLE getName() const noexcept; + + /** + * Set this View instance's Scene. + * + * @param scene Associate the specified Scene to this View. A Scene can be associated to + * several View instances.\n + * \p scene can be nullptr to dissociate the currently set Scene + * from this View.\n + * The View doesn't take ownership of the Scene pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a Scene from all Views before destroying it. + */ + void setScene(Scene* UTILS_NULLABLE scene); + + /** + * Returns the Scene currently associated with this View. + * @return A pointer to the Scene associated to this View. nullptr if no Scene is set. + */ + Scene* UTILS_NULLABLE getScene() noexcept; + + /** + * Returns the Scene currently associated with this View. + * @return A pointer to the Scene associated to this View. nullptr if no Scene is set. + */ + Scene const* UTILS_NULLABLE getScene() const noexcept { + return const_cast(this)->getScene(); + } + + /** + * Specifies an offscreen render target to render into. + * + * By default, the view's associated render target is nullptr, which corresponds to the + * SwapChain associated with the engine. + * + * A view with a custom render target cannot rely on Renderer::ClearOptions, which only apply + * to the SwapChain. Such view can use a Skybox instead. + * + * @param renderTarget Render target associated with view, or nullptr for the swap chain. + */ + void setRenderTarget(RenderTarget* UTILS_NULLABLE renderTarget) noexcept; + + /** + * Gets the offscreen render target associated with this view. + * + * Returns nullptr if the render target is the swap chain (which is default). + * + * @see setRenderTarget + */ + RenderTarget* UTILS_NULLABLE getRenderTarget() const noexcept; + + /** + * Sets the rectangular region to render to. + * + * The viewport specifies where the content of the View (i.e. the Scene) is rendered in + * the render target. The Render target is automatically clipped to the Viewport. + * + * @param viewport The Viewport to render the Scene into. The Viewport is a value-type, it is + * therefore copied. The parameter can be discarded after this call returns. + */ + void setViewport(Viewport const& viewport) noexcept; + + /** + * Returns the rectangular region that gets rendered to. + * @return A constant reference to View's viewport. + */ + Viewport const& getViewport() const noexcept; + + /** + * Sets this View's Camera. + * + * @param camera Associate the specified Camera to this View. A Camera can be associated to + * several View instances.\n + * \p camera can be nullptr to dissociate the currently set Camera from this + * View.\n + * The View doesn't take ownership of the Camera pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a Camera from all Views before destroying it. + */ + void setCamera(Camera* UTILS_NONNULL camera) noexcept; + + /** + * Returns the Camera currently associated with this View. + * @return A reference to the Camera associated to this View. + */ + Camera& getCamera() noexcept; + + /** + * Returns the Camera currently associated with this View. + * @return A reference to the Camera associated to this View. + */ + Camera const& getCamera() const noexcept { + return const_cast(this)->getCamera(); + } + + /** + * Sets the blending mode used to draw the view into the SwapChain. + * + * @param blendMode either BlendMode::OPAQUE or BlendMode::TRANSLUCENT + * @see getBlendMode + */ + void setBlendMode(BlendMode blendMode) noexcept; + + /** + * + * @return blending mode set by setBlendMode + * @see setBlendMode + */ + BlendMode getBlendMode() const noexcept; + + /** + * Sets which layers are visible. + * + * Renderable objects can have one or several layers associated to them. Layers are + * represented with an 8-bits bitmask, where each bit corresponds to a layer. + * + * This call sets which of those layers are visible. Renderables in invisible layers won't be + * rendered. + * + * @param select a bitmask specifying which layer to set or clear using \p values. + * @param values a bitmask where each bit sets the visibility of the corresponding layer + * (1: visible, 0: invisible), only layers in \p select are affected. + * + * @see RenderableManager::setLayerMask(). + * + * @note By default only layer 0 (bitmask 0x01) is visible. + * @note This is a convenient way to quickly show or hide sets of Renderable objects. + */ + void setVisibleLayers(uint8_t select, uint8_t values) noexcept; + + /** + * Helper function to enable or disable a visibility layer. + * @param layer layer between 0 and 7 to enable or disable + * @param enabled true to enable the layer, false to disable it + * @see RenderableManager::setVisibleLayers() + */ + inline void setLayerEnabled(size_t layer, bool enabled) noexcept { + const uint8_t mask = 1u << layer; + setVisibleLayers(mask, enabled ? mask : 0); + } + + /** + * Get the visible layers. + * + * @see View::setVisibleLayers() + */ + uint8_t getVisibleLayers() const noexcept; + + /** + * Enables or disables shadow mapping. Enabled by default. + * + * @param enabled true enables shadow mapping, false disables it. + * + * @see LightManager::Builder::castShadows(), + * RenderableManager::Builder::receiveShadows(), + * RenderableManager::Builder::castShadows(), + */ + void setShadowingEnabled(bool enabled) noexcept; + + /** + * @return whether shadowing is enabled + */ + bool isShadowingEnabled() const noexcept; + + /** + * Enables or disables screen space refraction. Enabled by default. + * + * @param enabled true enables screen space refraction, false disables it. + */ + void setScreenSpaceRefractionEnabled(bool enabled) noexcept; + + /** + * @return whether screen space refraction is enabled + */ + bool isScreenSpaceRefractionEnabled() const noexcept; + + /** + * Sets how many samples are to be used for MSAA in the post-process stage. + * Default is 1 and disables MSAA. + * + * @param count 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. + * + * @note Anti-aliasing can also be performed in the post-processing stage, generally at lower + * cost. See setAntialiasing. + * + * @see setAntialiasing + * @deprecated use setMultiSampleAntiAliasingOptions instead + */ + UTILS_DEPRECATED + void setSampleCount(uint8_t count = 1) noexcept; + + /** + * Returns the sample count set by setSampleCount(). Effective sample count could be different. + * A value of 0 or 1 means MSAA is disabled. + * + * @return value set by setSampleCount(). + * @deprecated use getMultiSampleAntiAliasingOptions instead + */ + UTILS_DEPRECATED + uint8_t getSampleCount() const noexcept; + + /** + * Enables or disables anti-aliasing in the post-processing stage. Enabled by default. + * MSAA can be enabled in addition, see setSampleCount(). + * + * @param type FXAA for enabling, NONE for disabling anti-aliasing. + * + * @note For MSAA anti-aliasing, see setSamplerCount(). + * + * @see setSampleCount + */ + void setAntiAliasing(AntiAliasing type) noexcept; + + /** + * Queries whether anti-aliasing is enabled during the post-processing stage. To query + * whether MSAA is enabled, see getSampleCount(). + * + * @return The post-processing anti-aliasing method. + */ + AntiAliasing getAntiAliasing() const noexcept; + + /** + * Enables or disable temporal anti-aliasing (TAA). Disabled by default. + * + * @param options temporal anti-aliasing options + */ + void setTemporalAntiAliasingOptions(TemporalAntiAliasingOptions options) noexcept; + + /** + * Returns temporal anti-aliasing options. + * + * @return temporal anti-aliasing options + */ + TemporalAntiAliasingOptions const& getTemporalAntiAliasingOptions() const noexcept; + + /** + * Enables or disable screen-space reflections. Disabled by default. + * + * @param options screen-space reflections options + */ + void setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions options) noexcept; + + /** + * Returns screen-space reflections options. + * + * @return screen-space reflections options + */ + ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept; + + /** + * Enables or disable screen-space guard band. Disabled by default. + * + * @param options guard band options + */ + void setGuardBandOptions(GuardBandOptions options) noexcept; + + /** + * Returns screen-space guard band options. + * + * @return guard band options + */ + GuardBandOptions const& getGuardBandOptions() const noexcept; + + /** + * Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default. + * + * @param options multi-sample anti-aliasing options + */ + void setMultiSampleAntiAliasingOptions(MultiSampleAntiAliasingOptions options) noexcept; + + /** + * Returns multi-sample anti-aliasing options. + * + * @return multi-sample anti-aliasing options + */ + MultiSampleAntiAliasingOptions const& getMultiSampleAntiAliasingOptions() const noexcept; + + /** + * Sets this View's color grading transforms. + * + * @param colorGrading Associate the specified ColorGrading to this View. A ColorGrading can be + * associated to several View instances.\n + * \p colorGrading can be nullptr to dissociate the currently set + * ColorGrading from this View. Doing so will revert to the use of the + * default color grading transforms.\n + * The View doesn't take ownership of the ColorGrading pointer (which + * acts as a reference). + * + * @note + * There is no reference-counting. + * Make sure to dissociate a ColorGrading from all Views before destroying it. + */ + void setColorGrading(ColorGrading* UTILS_NULLABLE colorGrading) noexcept; + + /** + * Returns the color grading transforms currently associated to this view. + * @return A pointer to the ColorGrading associated to this View. + */ + const ColorGrading* UTILS_NULLABLE getColorGrading() const noexcept; + + /** + * Sets ambient occlusion options. + * + * @param options Options for ambient occlusion. + */ + void setAmbientOcclusionOptions(AmbientOcclusionOptions const& options) noexcept; + + /** + * Gets the ambient occlusion options. + * + * @return ambient occlusion options currently set. + */ + AmbientOcclusionOptions const& getAmbientOcclusionOptions() const noexcept; + + /** + * Enables or disables bloom in the post-processing stage. Disabled by default. + * + * @param options options + */ + void setBloomOptions(BloomOptions options) noexcept; + + /** + * Queries the bloom options. + * + * @return the current bloom options for this view. + */ + BloomOptions getBloomOptions() const noexcept; + + /** + * Enables or disables fog. Disabled by default. + * + * @param options options + */ + void setFogOptions(FogOptions options) noexcept; + + /** + * Queries the fog options. + * + * @return the current fog options for this view. + */ + FogOptions getFogOptions() const noexcept; + + /** + * Enables or disables Depth of Field. Disabled by default. + * + * @param options options + */ + void setDepthOfFieldOptions(DepthOfFieldOptions options) noexcept; + + /** + * Queries the depth of field options. + * + * @return the current depth of field options for this view. + */ + DepthOfFieldOptions getDepthOfFieldOptions() const noexcept; + + /** + * Enables or disables the vignetted effect in the post-processing stage. Disabled by default. + * + * @param options options + */ + void setVignetteOptions(VignetteOptions options) noexcept; + + /** + * Queries the vignette options. + * + * @return the current vignette options for this view. + */ + VignetteOptions getVignetteOptions() const noexcept; + + /** + * Enables or disables dithering in the post-processing stage. Enabled by default. + * + * @param dithering dithering type + */ + void setDithering(Dithering dithering) noexcept; + + /** + * Queries whether dithering is enabled during the post-processing stage. + * + * @return the current dithering type for this view. + */ + Dithering getDithering() const noexcept; + + /** + * Sets the dynamic resolution options for this view. Dynamic resolution options + * controls whether dynamic resolution is enabled, and if it is, how it behaves. + * + * @param options The dynamic resolution options to use on this view + */ + void setDynamicResolutionOptions(DynamicResolutionOptions const& options) noexcept; + + /** + * Returns the dynamic resolution options associated with this view. + * @return value set by setDynamicResolutionOptions(). + */ + DynamicResolutionOptions getDynamicResolutionOptions() const noexcept; + + /** + * Sets the rendering quality for this view. Refer to RenderQuality for more + * information about the different settings available. + * + * @param renderQuality The render quality to use on this view + */ + void setRenderQuality(RenderQuality const& renderQuality) noexcept; + + /** + * Returns the render quality used by this view. + * @return value set by setRenderQuality(). + */ + RenderQuality getRenderQuality() const noexcept; + + /** + * Sets options relative to dynamic lighting for this view. + * + * @param zLightNear Distance from the camera where the lights are expected to shine. + * This parameter can affect performance and is useful because depending + * on the scene, lights that shine close to the camera may not be + * visible -- in this case, using a larger value can improve performance. + * e.g. when standing and looking straight, several meters of the ground + * isn't visible and if lights are expected to shine there, there is no + * point using a short zLightNear. (Default 5m). + * + * @param zLightFar Distance from the camera after which lights are not expected to be visible. + * Similarly to zLightNear, setting this value properly can improve + * performance. (Default 100m). + * + * + * Together zLightNear and zLightFar must be chosen so that the visible influence of lights + * is spread between these two values. + * + */ + void setDynamicLightingOptions(float zLightNear, float zLightFar) noexcept; + + /* + * Set the shadow mapping technique this View uses. + * + * The ShadowType affects all the shadows seen within the View. + * + * ShadowType::VSM imposes a restriction on marking renderables as only shadow receivers (but + * not casters). To ensure correct shadowing with VSM, all shadow participant renderables should + * be marked as both receivers and casters. Objects that are guaranteed to not cast shadows on + * themselves or other objects (such as flat ground planes) can be set to not cast shadows, + * which might improve shadow quality. + * + * @warning This API is still experimental and subject to change. + */ + void setShadowType(ShadowType shadow) noexcept; + + /** + * Sets VSM shadowing options that apply across the entire View. + * + * Additional light-specific VSM options can be set with LightManager::setShadowOptions. + * + * Only applicable when shadow type is set to ShadowType::VSM. + * + * @param options Options for shadowing. + * + * @see setShadowType + * + * @warning This API is still experimental and subject to change. + */ + void setVsmShadowOptions(VsmShadowOptions const& options) noexcept; + + /** + * Returns the VSM shadowing options associated with this View. + * + * @return value set by setVsmShadowOptions(). + */ + VsmShadowOptions getVsmShadowOptions() const noexcept; + + /** + * Sets soft shadowing options that apply across the entire View. + * + * Additional light-specific soft shadow parameters can be set with LightManager::setShadowOptions. + * + * Only applicable when shadow type is set to ShadowType::DPCF or ShadowType::PCSS. + * + * @param options Options for shadowing. + * + * @see setShadowType + * + * @warning This API is still experimental and subject to change. + */ + void setSoftShadowOptions(SoftShadowOptions const& options) noexcept; + + /** + * Returns the soft shadowing options associated with this View. + * + * @return value set by setSoftShadowOptions(). + */ + SoftShadowOptions getSoftShadowOptions() const noexcept; + + /** + * Enables or disables post processing. Enabled by default. + * + * Post-processing includes: + * - Depth-of-field + * - Bloom + * - Vignetting + * - Temporal Anti-aliasing (TAA) + * - Color grading & gamma encoding + * - Dithering + * - FXAA + * - Dynamic scaling + * + * Disabling post-processing forgoes color correctness as well as some anti-aliasing techniques + * and should only be used for debugging, UI overlays or when using custom render targets + * (see RenderTarget). + * + * @param enabled true enables post processing, false disables it. + * + * @see setBloomOptions, setColorGrading, setAntiAliasing, setDithering, setSampleCount + */ + void setPostProcessingEnabled(bool enabled) noexcept; + + //! Returns true if post-processing is enabled. See setPostProcessingEnabled() for more info. + bool isPostProcessingEnabled() const noexcept; + + /** + * Inverts the winding order of front faces. By default front faces use a counter-clockwise + * winding order. When the winding order is inverted, front faces are faces with a clockwise + * winding order. + * + * Changing the winding order will directly affect the culling mode in materials + * (see Material::getCullingMode()). + * + * Inverting the winding order of front faces is useful when rendering mirrored reflections + * (water, mirror surfaces, front camera in AR, etc.). + * + * @param inverted True to invert front faces, false otherwise. + */ + void setFrontFaceWindingInverted(bool inverted) noexcept; + + /** + * Returns true if the winding order of front faces is inverted. + * See setFrontFaceWindingInverted() for more information. + */ + bool isFrontFaceWindingInverted() const noexcept; + + /** + * Enables use of the stencil buffer. + * + * The stencil buffer is an 8-bit, per-fragment unsigned integer stored alongside the depth + * buffer. The stencil buffer is cleared at the beginning of a frame and discarded after the + * color pass. + * + * Each fragment's stencil value is set during rasterization by specifying stencil operations on + * a Material. The stencil buffer can be used as a mask for later rendering by setting a + * Material's stencil comparison function and reference value. Fragments that don't pass the + * stencil test are then discarded. + * + * If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER + * flag set in order to use the stencil buffer. + * + * A renderable's priority (see RenderableManager::setPriority) is useful to control the order + * in which primitives are drawn. + * + * @param enabled True to enable the stencil buffer, false disables it (default) + */ + void setStencilBufferEnabled(bool enabled) noexcept; + + /** + * Returns true if the stencil buffer is enabled. + * See setStencilBufferEnabled() for more information. + */ + bool isStencilBufferEnabled() const noexcept; + + /** + * Sets the stereoscopic rendering options for this view. + * + * Currently, only one type of stereoscopic rendering is supported: side-by-side. + * Side-by-side stereo rendering splits the viewport into two halves: a left and right half. + * Eye 0 will render to the left half, while Eye 1 will render into the right half. + * + * Currently, the following features are not supported with stereoscopic rendering: + * - post-processing + * - shadowing + * - punctual lights + * + * Stereo rendering depends on device and platform support. To check if stereo rendering is + * supported, use Engine::isStereoSupported(). If stereo rendering is not supported, then the + * stereoscopic options have no effect. + * + * @param options The stereoscopic options to use on this view + */ + void setStereoscopicOptions(StereoscopicOptions const& options) noexcept; + + /** + * Returns the stereoscopic options associated with this View. + * + * @return value set by setStereoscopicOptions(). + */ + StereoscopicOptions const& getStereoscopicOptions() const noexcept; + + // for debugging... + + //! debugging: allows to entirely disable frustum culling. (culling enabled by default). + void setFrustumCullingEnabled(bool culling) noexcept; + + //! debugging: returns whether frustum culling is enabled. + bool isFrustumCullingEnabled() const noexcept; + + //! debugging: sets the Camera used for rendering. It may be different from the culling camera. + void setDebugCamera(Camera* UTILS_NULLABLE camera) noexcept; + + //! debugging: returns a Camera from the point of view of *the* dominant directional light used for shadowing. + Camera const* UTILS_NULLABLE getDirectionalShadowCamera() const noexcept; + + + /** Result of a picking query */ + struct PickingQueryResult { + utils::Entity renderable{}; //! RenderableManager Entity at the queried coordinates + float depth{}; //! Depth buffer value (1 (near plane) to 0 (infinity)) + uint32_t reserved1{}; + uint32_t reserved2{}; + /** + * screen space coordinates in GL convention, this can be used to compute the view or + * world space position of the picking hit. For e.g.: + * clip_space_position = (fragCoords.xy / viewport.wh, fragCoords.z) * 2.0 - 1.0 + * view_space_position = inverse(projection) * clip_space_position + * world_space_position = model * view_space_position + * + * The viewport, projection and model matrices can be obtained from Camera. Because + * pick() has some latency, it might be more accurate to obtain these values at the + * time the View::pick() call is made. + * + * Note: if the Engine is running at FEATURE_LEVEL_0, the precision or `depth` and + * `fragCoords.z` is only 8-bits. + */ + math::float3 fragCoords; //! screen space coordinates in GL convention + }; + + /** User data for PickingQueryResultCallback */ + struct PickingQuery { + // note: this is enough to store a std::function<> -- just saying... + void* UTILS_NULLABLE storage[4]; + }; + + /** callback type used for picking queries. */ + using PickingQueryResultCallback = + void(*)(PickingQueryResult const& result, PickingQuery* UTILS_NONNULL pq); + + /** + * Helper for creating a picking query from Foo::method, by pointer. + * e.g.: pick(x, y, &foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param instance A pointer to an instance of T + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T* UTILS_NONNULL instance, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + (static_cast(pq->storage[0])->*method)(result); + }, handler); + query.storage[0] = instance; + } + + /** + * Helper for creating a picking query from Foo::method, by copy for a small object + * e.g.: pick(x, y, foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param instance An instance of T + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T instance, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + static_assert(sizeof(instance) <= sizeof(PickingQuery::storage), "user data too large"); + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + T* const that = static_cast(reinterpret_cast(pq->storage)); + (that->*method)(result); + that->~T(); + }, handler); + new(query.storage) T(std::move(instance)); + } + + /** + * Helper for creating a picking query from a small functor + * e.g.: pick(x, y, [](PickingQueryResult const& result){}); + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param functor A functor, typically a lambda function. + * @param handler Handler to dispatch the callback or nullptr for the default handler. + */ + template + void pick(uint32_t x, uint32_t y, T functor, + backend::CallbackHandler* UTILS_NULLABLE handler = nullptr) noexcept { + static_assert(sizeof(functor) <= sizeof(PickingQuery::storage), "functor too large"); + PickingQuery& query = pick(x, y, handler, + (PickingQueryResultCallback)[](PickingQueryResult const& result, PickingQuery* pq) { + T* const that = static_cast(reinterpret_cast(pq->storage)); + that->operator()(result); + that->~T(); + }); + new(query.storage) T(std::move(functor)); + } + + /** + * Creates a picking query. Multiple queries can be created (e.g.: multi-touch). + * Picking queries are all executed when Renderer::render() is called on this View. + * The provided callback is guaranteed to be called at some point in the future. + * + * Typically it takes a couple frames to receive the result of a picking query. + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param callback User callback, called when the picking query result is available. + * @param handler Handler to dispatch the callback or nullptr for the default handler. + * @return A reference to a PickingQuery structure, which can be used to store up to + * 8*sizeof(void*) bytes of user data. This user data is later accessible + * in the PickingQueryResultCallback callback 3rd parameter. + */ + PickingQuery& pick(uint32_t x, uint32_t y, + backend::CallbackHandler* UTILS_NULLABLE handler, + PickingQueryResultCallback UTILS_NONNULL callback) noexcept; + + /** + * Set the value of material global variables. There are up-to four such variable each of + * type float4. These variables can be read in a user Material with + * `getMaterialGlobal{0|1|2|3}()`. All variable start with a default value of { 0, 0, 0, 1 } + * + * @param index index of the variable to set between 0 and 3. + * @param value new value for the variable. + * @see getMaterialGlobal + */ + void setMaterialGlobal(uint32_t index, math::float4 const& value); + + /** + * Get the value of the material global variables. + * All variable start with a default value of { 0, 0, 0, 1 } + * + * @param index index of the variable to set between 0 and 3. + * @return current value of the variable. + * @see setMaterialGlobal + */ + math::float4 getMaterialGlobal(uint32_t index) const; + + /** + * Get an Entity representing the large scale fog object. + * This entity is always inherited by the View's Scene. + * + * It is for example possible to create a TransformManager component with this + * Entity and apply a transformation globally on the fog. + * + * @return an Entity representing the large scale fog object. + */ + utils::Entity getFogEntity() const noexcept; + + /** + * List of available ambient occlusion techniques + * @deprecated use AmbientOcclusionOptions::enabled instead + */ + enum class UTILS_DEPRECATED AmbientOcclusion : uint8_t { + NONE = 0, //!< No Ambient Occlusion + SSAO = 1 //!< Basic, sampling SSAO + }; + + /** + * Activates or deactivates ambient occlusion. + * @deprecated use setAmbientOcclusionOptions() instead + * @see setAmbientOcclusionOptions + * + * @param ambientOcclusion Type of ambient occlusion to use. + */ + UTILS_DEPRECATED + void setAmbientOcclusion(AmbientOcclusion ambientOcclusion) noexcept; + + /** + * Queries the type of ambient occlusion active for this View. + * @deprecated use getAmbientOcclusionOptions() instead + * @see getAmbientOcclusionOptions + * + * @return ambient occlusion type. + */ + UTILS_DEPRECATED + AmbientOcclusion getAmbientOcclusion() const noexcept; + +protected: + // prevent heap allocation + ~View() = default; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VIEW_H diff --git a/package/ios/libs/filament/include/filament/Viewport.h b/package/ios/libs/filament/include/filament/Viewport.h new file mode 100644 index 00000000..29916f70 --- /dev/null +++ b/package/ios/libs/filament/include/filament/Viewport.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 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. + */ + +//! \file + +#ifndef TNT_FILAMENT_VIEWPORT_H +#define TNT_FILAMENT_VIEWPORT_H + +#include + +#include + +#include +#include + +namespace filament { + +/** + * Viewport describes a view port in pixel coordinates + * + * A view port is represented by its left-bottom coordinate, width and height in pixels. + */ +class UTILS_PUBLIC Viewport : public backend::Viewport { +public: + /** + * Creates a Viewport of zero width and height at the origin. + */ + Viewport() noexcept : backend::Viewport{} {} + + /** + * Creates a Viewport from its left-bottom coordinates, width and height in pixels + * + * @param left left coordinate in pixel + * @param bottom bottom coordinate in pixel + * @param width width in pixel + * @param height height in pixel + */ + Viewport(int32_t left, int32_t bottom, uint32_t width, uint32_t height) noexcept + : backend::Viewport{ left, bottom, width, height } { + } + + /** + * Returns whether the area of the view port is null. + * + * @return true if either width or height is 0 pixel. + */ + bool empty() const noexcept { return !width || !height; } + +private: + /** + * Compares two Viewports for equality + * @param lhs reference to the left hand side Viewport + * @param rhs reference to the right hand side Viewport + * @return true if \p rhs and \p lhs are identical. + */ + friend bool operator==(Viewport const& lhs, Viewport const& rhs) noexcept { + return (&rhs == &lhs) || + (rhs.left == lhs.left && rhs.bottom == lhs.bottom && + rhs.width == lhs.width && rhs.height == lhs.height); + } + + /** + * Compares two Viewports for inequality + * @param lhs reference to the left hand side Viewport + * @param rhs reference to the right hand side Viewport + * @return true if \p rhs and \p lhs are different. + */ + friend bool operator!=(Viewport const& lhs, Viewport const& rhs) noexcept { + return !(rhs == lhs); + } +}; + +} // namespace filament + +#endif // TNT_FILAMENT_VIEWPORT_H diff --git a/package/ios/libs/filament/include/filameshio/MeshReader.h b/package/ios/libs/filament/include/filameshio/MeshReader.h new file mode 100644 index 00000000..22533791 --- /dev/null +++ b/package/ios/libs/filament/include/filameshio/MeshReader.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_FILAMENT_FILAMESHIO_MESHREADER_H +#define TNT_FILAMENT_FILAMESHIO_MESHREADER_H + +#include +#include +#include + +namespace filament { + class Engine; + class VertexBuffer; + class IndexBuffer; + class MaterialInstance; +} + +namespace utils { + class Path; +} + +namespace filamesh { + + +/** + * This API can be used to read meshes stored in the "filamesh" format produced + * by the command line tool of the same name. This file format is documented in + * "docs/filamesh.md" in the Filament distribution. + */ +class UTILS_PUBLIC MeshReader { +public: + using Callback = void(*)(void* buffer, size_t size, void* user); + + // Class to track material instances + class MaterialRegistry { + public: + MaterialRegistry(); + MaterialRegistry(const MaterialRegistry& rhs); + MaterialRegistry& operator=(const MaterialRegistry& rhs); + ~MaterialRegistry(); + MaterialRegistry(MaterialRegistry&&); + MaterialRegistry& operator=(MaterialRegistry&&); + + filament::MaterialInstance* getMaterialInstance(const utils::CString& name); + + void registerMaterialInstance(const utils::CString& name, + filament::MaterialInstance* materialInstance); + + void unregisterMaterialInstance(const utils::CString& name); + + void unregisterAll(); + + size_t numRegistered() const noexcept; + + void getRegisteredMaterials(filament::MaterialInstance** materialList, + utils::CString* materialNameList) const; + + void getRegisteredMaterials(filament::MaterialInstance** materialList) const; + + void getRegisteredMaterialNames(utils::CString* materialNameList) const; + + private: + struct MaterialRegistryImpl; + MaterialRegistryImpl* mImpl; + }; + + struct Mesh { + utils::Entity renderable; + filament::VertexBuffer* vertexBuffer = nullptr; + filament::IndexBuffer* indexBuffer = nullptr; + }; + + /** + * Loads a filamesh renderable from the specified file. The material registry + * can be used to provide named materials. If a material found in the filamesh + * file cannot be matched to a material in the registry, a default material is + * used instead. The default material can be overridden by adding a material + * named "DefaultMaterial" to the registry. + */ + static Mesh loadMeshFromFile(filament::Engine* engine, + const utils::Path& path, + MaterialRegistry& materials); + + /** + * Loads a filamesh renderable from an in-memory buffer. The material registry + * can be used to provide named materials. If a material found in the filamesh + * file cannot be matched to a material in the registry, a default material is + * used instead. The default material can be overridden by adding a material + * named "DefaultMaterial" to the registry. + */ + static Mesh loadMeshFromBuffer(filament::Engine* engine, + void const* data, Callback destructor, void* user, + MaterialRegistry& materials); + + /** + * Loads a filamesh renderable from an in-memory buffer. The material registry + * can be used to provide named materials. All the primitives of the decoded + * renderable are assigned the specified default material. + */ + static Mesh loadMeshFromBuffer(filament::Engine* engine, + void const* data, Callback destructor, void* user, + filament::MaterialInstance* defaultMaterial); +}; + +} // namespace filamesh + +#endif // TNT_FILAMENT_FILAMESHIO_MESHREADER_H diff --git a/package/ios/libs/filament/include/geometry/SurfaceOrientation.h b/package/ios/libs/filament/include/geometry/SurfaceOrientation.h new file mode 100644 index 00000000..e9ad75bb --- /dev/null +++ b/package/ios/libs/filament/include/geometry/SurfaceOrientation.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_GEOMETRY_SURFACEORIENTATION_H +#define TNT_GEOMETRY_SURFACEORIENTATION_H + +#include +#include +#include + +#include + +namespace filament { + +/** + * Mesh-related utilities. + */ +namespace geometry { + +struct OrientationBuilderImpl; +struct OrientationImpl; + +/** + * The surface orientation helper can be used to populate Filament-style TANGENTS buffers. + */ +class UTILS_PUBLIC SurfaceOrientation { +public: + + /** + * The Builder is used to construct an immutable surface orientation helper. + * + * Clients provide pointers into their own data, which is synchronously consumed during build(). + * At a minimum, clients must supply a vertex count. They can supply data in any of the + * following combinations: + * + * 1. normals only ........................... not recommended, selects arbitrary orientation + * 2. normals + tangents ..................... sign of W determines bitangent orientation + * 3. normals + uvs + positions + indices .... selects Lengyel’s Method + * 4. positions + indices .................... generates normals for flat shading only + * + * Additionally, the client-side data has the following type constraints: + * + * - Normals must be float3 + * - Tangents must be float4 + * - UVs must be float2 + * - Positions must be float3 + * - Triangles must be uint3 or ushort3 + * + * Currently, mikktspace is not supported because it requires re-indexing the mesh. Instead + * we use the method described by Eric Lengyel in "Foundations of Game Engine Development" + * (Volume 2, Chapter 7). + */ + class Builder { + public: + Builder() noexcept; + ~Builder() noexcept; + Builder(Builder&& that) noexcept; + Builder& operator=(Builder&& that) noexcept; + + /** + * This attribute is required. + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + Builder& normals(const filament::math::float3*, size_t stride = 0) noexcept; + Builder& tangents(const filament::math::float4*, size_t stride = 0) noexcept; + Builder& uvs(const filament::math::float2*, size_t stride = 0) noexcept; + Builder& positions(const filament::math::float3*, size_t stride = 0) noexcept; + + Builder& triangleCount(size_t triangleCount) noexcept; + Builder& triangles(const filament::math::uint3*) noexcept; + Builder& triangles(const filament::math::ushort3*) noexcept; + + /** + * Generates quats or returns null if the submitted data is an incomplete combination. + */ + SurfaceOrientation* build(); + + private: + OrientationBuilderImpl* mImpl; + Builder(const Builder&) = delete; + Builder& operator=(const Builder&) = delete; + }; + + ~SurfaceOrientation() noexcept; + SurfaceOrientation(SurfaceOrientation&& that) noexcept; + SurfaceOrientation& operator=(SurfaceOrientation&& that) noexcept; + + /** + * Returns the vertex count. + */ + size_t getVertexCount() const noexcept; + + /** + * Converts quaternions into the desired output format and writes up to "quatCount" + * to the given output pointer. Normally quatCount should be equal to the vertex count. + * The optional stride is the desired quat-to-quat stride in bytes. + * @{ + */ + void getQuats(filament::math::quatf* out, size_t quatCount, size_t stride = 0) const noexcept; + void getQuats(filament::math::short4* out, size_t quatCount, size_t stride = 0) const noexcept; + void getQuats(filament::math::quath* out, size_t quatCount, size_t stride = 0) const noexcept; + /** + * @} + */ + +private: + SurfaceOrientation(OrientationImpl*) noexcept; + SurfaceOrientation(const SurfaceOrientation&) = delete; + SurfaceOrientation& operator=(const SurfaceOrientation&) = delete; + OrientationImpl* mImpl; + friend struct OrientationBuilderImpl; +}; + +} // namespace geometry +} // namespace filament + +#endif // TNT_GEOMETRY_SURFACEORIENTATION_H diff --git a/package/ios/libs/filament/include/geometry/TangentSpaceMesh.h b/package/ios/libs/filament/include/geometry/TangentSpaceMesh.h new file mode 100644 index 00000000..980e81ac --- /dev/null +++ b/package/ios/libs/filament/include/geometry/TangentSpaceMesh.h @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef TNT_GEOMETRY_TANGENTSPACEMESH_H +#define TNT_GEOMETRY_TANGENTSPACEMESH_H + +#include +#include +#include + +#include + +namespace filament { +namespace geometry { + +struct TangentSpaceMeshInput; +struct TangentSpaceMeshOutput; + + /** + * This class builds Filament-style TANGENTS buffers given an input mesh. + * + * This class enables the client to chose between several algorithms. The client can retrieve the + * result through the `get` methods on the class. If the chosen algorithm did not remesh the input, + * the client is advised to just use the data they provided instead of querying. For example, if + * the chosen method is Algorithm::FRISVAD, then the client should not need to call getPositions(). + * We will simply copy from the input `positions` in that case. + * + * If the client calls getPositions() and positions were not provided as input, we will throw + * and exception. Similar behavior will apply to UVs. + * + * This class supersedes the implementation in SurfaceOrientation.h + */ +class TangentSpaceMesh { +public: + enum class Algorithm : uint8_t { + /** + * default + * + * Tries to select the best possible algorithm given the input. The corresponding algorithms + * are detailed in the corresponding enums. + *
+         *   INPUT                                  ALGORITHM
+         *   -----------------------------------------------------------
+         *   normals                                FRISVAD
+         *   positions + indices                    FLAT_SHADING
+         *   normals + uvs + positions + indices    MIKKTSPACE
+         * 
+ */ + DEFAULT = 0, + + /** + * mikktspace + * + * **Requires**: `normals + uvs + positions + indices`
+ * **Reference**: + * - Mikkelsen, M., 2008. Simulation of wrinkled surfaces revisited. + * - https://github.com/mmikk/MikkTSpace + * - https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview + * + * **Note**: Will remesh + */ + MIKKTSPACE = 1, + + /** + * Lengyel's method + * + * **Requires**: `normals + uvs + positions + indices`
+ * **Reference**: Lengyel, E., 2019. Foundations of Game Engine Development: Rendering. Terathon + * Software LLC.. (Chapter 7) + */ + LENGYEL = 2, + + /** + * Hughes-Moller method + * + * **Requires**: `normals`
+ * **Reference**: + * - Hughes, J.F. and Moller, T., 1999. Building an orthonormal basis from a unit + * vector. journal of graphics tools, 4(4), pp.33-35. + * - Parker, S.G., Bigler, J., Dietrich, A., Friedrich, H., Hoberock, J., Luebke, D., + * McAllister, D., McGuire, M., Morley, K., Robison, A. and Stich, M., 2010. + * Optix: a general purpose ray tracing engine. Acm transactions on graphics (tog), + * 29(4), pp.1-13. + * **Note**: We implement the Optix variant, which is documented in the second reference above. + */ + HUGHES_MOLLER = 3, + + /** + * Frisvad's method + * + * **Requires**: `normals`
+ * **Reference**: + * - Frisvad, J.R., 2012. Building an orthonormal basis from a 3D unit vector without + * normalization. Journal of Graphics Tools, 16(3), pp.151-159. + * - http://people.compute.dtu.dk/jerf/code/hairy/ + */ + FRISVAD = 4, + }; + + /** + * This enum specifies the auxiliary attributes of each vertex that can be provided as input. + * These attributes do not affect the computation of the tangent space, but they will be + * properly mapped when a remeshing is carried out. + */ + enum class AuxAttribute : uint8_t { + UV1 = 0x0, + COLORS = 0x1, + JOINTS = 0x2, + WEIGHTS = 0x3, + }; + + using InData = std::variant; + + /** + * Use this class to provide input to the TangentSpaceMesh computation. **Important**: + * Computation of the tangent space is intended to be synchronous (working on the same thread). + * Client is expected to keep the input immutable and in a good state for the duration of both + * computation *and* query. That is, when querying the result of the tangent spaces, part of the + * result might depend on the input data. + */ + class Builder { + public: + Builder() noexcept; + ~Builder() noexcept; + + /** + * Move constructor + */ + Builder(Builder&& that) noexcept; + + /** + * Move constructor + */ + Builder& operator=(Builder&& that) noexcept; + + Builder(Builder const&) = delete; + Builder& operator=(Builder const&) = delete; + + /** + * Client must provide this parameter + * + * @param vertexCount The input number of vertcies + */ + Builder& vertexCount(size_t vertexCount) noexcept; + + /** + * @param normals The input normals + * @param stride The stride for iterating through `normals` + * @return Builder + */ + Builder& normals(filament::math::float3 const* normals, size_t stride = 0) noexcept; + + /** + * @param tangents The input tangents. The `w` component is for use with + * Algorithm::SIGN_OF_W. + * @param stride The stride for iterating through `tangents` + * @return Builder + */ + Builder& tangents(filament::math::float4 const* tangents, size_t stride = 0) noexcept; + + /** + * @param uvs The input uvs + * @param stride The stride for iterating through `uvs` + * @return Builder + */ + Builder& uvs(filament::math::float2 const* uvs, size_t stride = 0) noexcept; + + /** + * Sets "auxiliary" attributes that will be properly mapped when remeshed. + * + * @param attribute The attribute of the data to be stored + * @param data The data to be store + * @param stride The stride for iterating through `attribute` + * @return Builder + */ + Builder& aux(AuxAttribute attribute, InData data, size_t stride = 0) noexcept; + + /** + * @param positions The input positions + * @param stride The stride for iterating through `positions` + * @return Builder + */ + Builder& positions(filament::math::float3 const* positions, size_t stride = 0) noexcept; + + /** + * @param triangleCount The input number of triangles + * @return Builder + */ + Builder& triangleCount(size_t triangleCount) noexcept; + + /** + * @param triangles The triangles in 32-bit indices + * @return Builder + */ + Builder& triangles(filament::math::uint3 const* triangles) noexcept; + + /** + * @param triangles The triangles in 16-bit indices + * @return Builder + */ + Builder& triangles(filament::math::ushort3 const* triangles) noexcept; + + /** + * The Client can provide an algorithm hint to produce the tangents. + * + * @param algorithm The algorithm hint. + * @return Builder + */ + Builder& algorithm(Algorithm algorithm) noexcept; + + /** + * Computes the tangent space mesh. The resulting mesh object is owned by the callee. The + * callee must call TangentSpaceMesh::destroy on the object once they are finished with it. + * + * The state of the Builder will be reset after each call to build(). The client needs to + * populate the builder with parameters again if they choose to re-use it. + * + * @return A TangentSpaceMesh + */ + TangentSpaceMesh* build(); + + private: + TangentSpaceMesh* mMesh = nullptr; + }; + + /** + * Destroy the mesh object + * @param mesh A pointer to a TangentSpaceMesh ready to be destroyed + */ + static void destroy(TangentSpaceMesh* mesh) noexcept; + + /** + * Move constructor + */ + TangentSpaceMesh(TangentSpaceMesh&& that) noexcept; + + /** + * Move constructor + */ + TangentSpaceMesh& operator=(TangentSpaceMesh&& that) noexcept; + + TangentSpaceMesh(TangentSpaceMesh const&) = delete; + TangentSpaceMesh& operator=(TangentSpaceMesh const&) = delete; + + /** + * Number of output vertices + * + * The number of output vertices can be the same as the input if the selected algorithm did not + * "remesh" the input. + * + * @return The number of vertices + */ + size_t getVertexCount() const noexcept; + + /** + * Get output vertex positions. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). The output vertices can be the same as the input if the selected algorithm did + * not "remesh" the input. The remeshed vertices are not guarranteed to have correlation in + * order with the input mesh. + * + * @param out Client-allocated array that will be used for copying out positions. + * @param stride Stride for iterating through `out` + */ + void getPositions(filament::math::float3* out, size_t stride = 0) const; + + /** + * Get output UVs. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). The output uvs can be the same as the input if the selected algorithm did + * not "remesh" the input. The remeshed UVs are not guarranteed to have correlation in order + * with the input mesh. + * + * @param out Client-allocated array that will be used for copying out UVs. + * @param stride Stride for iterating through `out` + */ + void getUVs(filament::math::float2* out, size_t stride = 0) const; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 32-bit floating points. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::quatf* out, size_t stride = 0) const noexcept; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 16-bit signed integers. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::short4* out, size_t stride = 0) const noexcept; + + /** + * Get output tangent space. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out tangent space in + * 16-bit floating points. + * @param stride Stride for iterating through `out` + */ + void getQuats(filament::math::quath* out, size_t stride = 0) const noexcept; + + /** + * Get output auxiliary attributes. + * Assumes the `out` param is at least of getVertexCount() length (while accounting for + * `stride`). + * + * @param out Client-allocated array that will be used for copying out attribute as T + * @param stride Stride for iterating through `out` + */ + template + using is_supported_aux_t = + typename std::enable_if::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>::type; + template> + void getAux(AuxAttribute attribute, T* out, size_t stride = 0) const noexcept; + + /** + * Get number of output triangles. + * The number of output triangles is the same as the number of input triangles. However, when a + * "remesh" is carried out the output triangles are not guarranteed to have any correlation with + * the input. + * + * @return The number of vertices + */ + size_t getTriangleCount() const noexcept; + + /** + * Get output triangles. + * This method assumes that the `out` param provided by the client is at least of + * getTriangleCount() length. If the client calls getTriangles() and triangles were not + * provided as input, we will throw and exception. + * + * @param out Client's array for the output triangles in unsigned 32-bit indices. + */ + void getTriangles(filament::math::uint3* out) const; + + /** + * Get output triangles. + * This method assumes that the `out` param provided by the client is at least of + * getTriangleCount() length. If the client calls getTriangles() and triangles were not + * provided as input, we will throw and exception. + * + * @param out Client's array for the output triangles in unsigned 16-bit indices. + */ + void getTriangles(filament::math::ushort3* out) const; + + /** + * @return Whether the TBN algorithm remeshed the input. + */ + bool remeshed() const noexcept; + +private: + ~TangentSpaceMesh() noexcept; + TangentSpaceMesh() noexcept; + TangentSpaceMeshInput* mInput; + TangentSpaceMeshOutput* mOutput; + + friend class Builder; +}; + +} // namespace geometry +} // namespace filament + +#endif //TNT_GEOMETRY_TANGENTSPACEMESH_H diff --git a/package/ios/libs/filament/include/geometry/Transcoder.h b/package/ios/libs/filament/include/geometry/Transcoder.h new file mode 100644 index 00000000..805c2609 --- /dev/null +++ b/package/ios/libs/filament/include/geometry/Transcoder.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_GEOMETRY_TRANSCODER_H +#define TNT_GEOMETRY_TRANSCODER_H + +#include + +#include +#include + +namespace filament { +namespace geometry { + +enum class ComponentType { + BYTE, //!< If normalization is enabled, this maps from [-127,127] to [-1,+1] + UBYTE, //!< If normalization is enabled, this maps from [0,255] to [0, +1] + SHORT, //!< If normalization is enabled, this maps from [-32767,32767] to [-1,+1] + USHORT, //!< If normalization is enabled, this maps from [0,65535] to [0, +1] + HALF, //!< 1 sign bit, 5 exponent bits, and 5 mantissa bits. + FLOAT, //!< Standard 32-bit float +}; + +/** + * Creates a function object that can convert vertex attribute data into tightly packed floats. + * + * This is especially useful for 3-component formats which are not supported by all backends. + * e.g. The Vulkan minspec includes float3 but not short3. + * + * Usage Example: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * using filament::geometry::Transcoder; + * using filament::geometry::ComponentType; + * + * Transcoder transcode({ + * .componentType = ComponentType::BYTE, + * .normalized = true, + * .componentCount = 3, + * .inputStrideBytes = 0 + * }); + * + * transcode(outputPtr, inputPtr, count); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The interpretation of signed normalized data is consistent with Vulkan and OpenGL ES 3.0+. + * Note that this slightly differs from earlier versions of OpenGL ES. For example, a signed byte + * value of -127 maps exactly to -1.0f under ES3 and VK rules, but not ES2. + */ +class UTILS_PUBLIC Transcoder { +public: + /** + * Describes the format of all input data that get passed to this transcoder object. + */ + struct Config { + ComponentType componentType; + bool normalized; + uint32_t componentCount; + uint32_t inputStrideBytes = 0; //!< If stride is 0, the transcoder assumes tight packing. + }; + + /** + * Creates an immutable function object with the specified configuration. + * + * The config is not passed by const reference to allow for type inference at the call site. + */ + Transcoder(Config config) noexcept : mConfig(config) {} + + /** + * Converts arbitrary data into tightly packed 32-bit floating point values. + * + * If target is non-null, writes up to "count" items into target and returns the number of bytes + * actually written. + * + * If target is null, returns the number of bytes required. + * + * @param target Client owned area to write into, or null for a size query + * @param source Pointer to the data to read from (does not get retained) + * @param count The maximum number of items to write (i.e. number of float3 values, not bytes) + * @return Number of bytes required to contain "count" items after conversion to packed floats + * + */ + size_t operator()(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, + size_t count) const noexcept; + +private: + const Config mConfig; +}; + +} // namespace geometry +} // namespace filament + +#endif // TNT_GEOMETRY_TRANSCODER_H diff --git a/package/ios/libs/filament/include/gltfio/Animator.h b/package/ios/libs/filament/include/gltfio/Animator.h new file mode 100644 index 00000000..199555a4 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/Animator.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_ANIMATOR_H +#define GLTFIO_ANIMATOR_H + +#include +#include + +namespace filament::gltfio { + +struct FFilamentAsset; +struct FFilamentInstance; +struct AnimatorImpl; + +/** + * \class Animator Animator.h gltfio/Animator.h + * \brief Updates matrices according to glTF \c animation and \c skin definitions. + * + * Animator can be used for two things: + * - Updating matrices in filament::TransformManager components according to glTF \c animation definitions. + * - Updating bone matrices in filament::RenderableManager components according to glTF \c skin definitions. + * + * For a usage example, see the documentation for AssetLoader. + */ +class UTILS_PUBLIC Animator { +public: + /** + * Applies rotation, translation, and scale to entities that have been targeted by the given + * animation definition. Uses filament::TransformManager. + * + * @param animationIndex Zero-based index for the \c animation of interest. + * @param time Elapsed time of interest in seconds. + */ + void applyAnimation(size_t animationIndex, float time) const; + + /** + * Computes root-to-node transforms for all bone nodes, then passes + * the results into filament::RenderableManager::setBones. + * Uses filament::TransformManager and filament::RenderableManager. + * + * NOTE: this operation is independent of \c animation. + */ + 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. + * + * NOTE: this operation is independent of \c animation. + */ + void resetBoneMatrices(); + + /** Returns the number of \c animation definitions in the glTF asset. */ + size_t getAnimationCount() const; + + /** Returns the duration of the specified glTF \c animation in seconds. */ + float getAnimationDuration(size_t animationIndex) const; + + /** + * Returns a weak reference to the string name of the specified \c animation, or an + * empty string if none was specified. + */ + const char* getAnimationName(size_t animationIndex) const; + + // For internal use only. + void addInstance(FFilamentInstance* instance); + +private: + + /*! \cond PRIVATE */ + friend struct FFilamentAsset; + friend struct FFilamentInstance; + /*! \endcond */ + + // If "instance" is null, then this is the primary animator. + Animator(FFilamentAsset const* asset, FFilamentInstance* instance); + ~Animator(); + + Animator(const Animator& animator) = delete; + Animator(Animator&& animator) = delete; + Animator& operator=(const Animator&) = delete; + + AnimatorImpl* mImpl; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_ANIMATOR_H diff --git a/package/ios/libs/filament/include/gltfio/AssetLoader.h b/package/ios/libs/filament/include/gltfio/AssetLoader.h new file mode 100644 index 00000000..080538aa --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/AssetLoader.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_ASSETLOADER_H +#define GLTFIO_ASSETLOADER_H + +#include +#include + +#include +#include +#include + +#include + +namespace utils { + class EntityManager; + class NameComponentManager; +} + +/** + * Loader and pipeline for glTF 2.0 assets. + */ +namespace filament::gltfio { + +class NodeManager; + +/** + * \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h + * \brief Construction parameters for AssetLoader. + */ +struct AssetConfiguration { + //! The engine that the loader should pass to builder objects (e.g. + //! filament::VertexBuffer::Builder). + class filament::Engine* engine; + + //! Controls whether the loader uses filamat to generate materials on the fly, or loads a small + //! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's + //! responsibility. See createJitShaderProvider() and createUbershaderProvider(). + MaterialProvider* materials; + + //! Optional manager for associating string names with entities in the transform hierarchy. + utils::NameComponentManager* names = nullptr; + + //! Overrides the factory used for creating entities in the transform hierarchy. If this is not + //! specified, AssetLoader will use the singleton EntityManager associated with the current + //! process. + utils::EntityManager* entities = nullptr; + + //! Optional default node name for anonymous nodes + char* defaultNodeName = nullptr; +}; + +/** + * \class AssetLoader AssetLoader.h gltfio/AssetLoader.h + * \brief Consumes glTF content and produces FilamentAsset objects. + * + * AssetLoader consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a FilamentAsset + * object, which is a bundle of Filament textures, vertex buffers, index buffers, etc. An asset is + * composed of 1 or more FilamentInstance objects which contain entities and components. + * + * Clients must use AssetLoader to create and destroy FilamentAsset objects. This is similar to + * how filament::Engine is used to create and destroy core objects like VertexBuffer. + * + * AssetLoader does not fetch external buffer data or create textures on its own. Clients can use + * ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the + * code snippet below. + * + * AssetLoader also owns a cache of filament::Material objects that may be re-used across multiple + * loads. + * + * Example usage: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto engine = Engine::create(); + * auto materials = createJitShaderProvider(engine); + * auto decoder = createStbProvider(engine); + * auto loader = AssetLoader::create({engine, materials}); + * + * // Parse the glTF content and create Filament entities. + * std::vector content(...); + * FilamentAsset* asset = loader->createAsset(content.data(), content.size()); + * content.clear(); + * + * // Load buffers and textures from disk. + * ResourceLoader resourceLoader({engine, ".", true}); + * resourceLoader.addTextureProvider("image/png", decoder) + * resourceLoader.addTextureProvider("image/jpeg", decoder) + * resourceLoader.loadResources(asset); + * + * // Free the glTF hierarchy as it is no longer needed. + * asset->releaseSourceData(); + * + * // Add renderables to the scene. + * scene->addEntities(asset->getEntities(), asset->getEntityCount()); + * + * // Extract the animator interface from the FilamentInstance. + * auto animator = asset->getInstance()->getAnimator(); + * + * // Execute the render loop and play the first animation. + * do { + * animator->applyAnimation(0, time); + * animator->updateBoneMatrices(); + * if (renderer->beginFrame(swapChain)) { + * renderer->render(view); + * renderer->endFrame(); + * } + * } while (!quit); + * + * scene->removeEntities(asset->getEntities(), asset->getEntityCount()); + * loader->destroyAsset(asset); + * materials->destroyMaterials(); + * delete materials; + * delete decoder; + * AssetLoader::destroy(&loader); + * Engine::destroy(&engine); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC AssetLoader { +public: + + /** + * Creates an asset loader for the given configuration, which specifies the Filament engine. + * + * The engine is held weakly, used only for the creation and destruction of Filament objects. + * The optional name component manager can be used to assign names to renderables. + * The material source specifies whether to use filamat to generate materials on the fly, or to + * load a small set of precompiled ubershader materials. + */ + static AssetLoader* create(const AssetConfiguration& config); + + /** + * Frees the loader. + * + * This does not not automatically free the cache of materials, nor + * does it free the entities for created assets (see destroyAsset). + */ + static void destroy(AssetLoader** loader); + + /** + * Takes a pointer to the contents of a GLB or a JSON-based glTF 2.0 file and returns an asset + * with one instance, or null on failure. + */ + FilamentAsset* createAsset(const uint8_t* bytes, uint32_t nbytes); + + /** + * Consumes the contents of a glTF 2.0 file and produces a primary asset with one or more + * instances. The primary asset has ownership over the instances. + * + * The returned instances share their textures, materials, and vertex buffers with the primary + * asset. However each instance has its own unique set of entities, transform components, + * material instances, and renderable components. Instances are freed when the primary asset is + * freed. + * + * Light components are not instanced, they belong only to the primary asset. + * + * Clients must use ResourceLoader to load resources on the primary asset. + * + * The entity accessor and renderable stack API in the primary asset can be used to control the + * union of all instances. The individual FilamentInstance objects can be used to access each + * instance's partition of entities. Similarly, the Animator in the primary asset controls all + * instances. To animate instances individually, use FilamentInstance::getAnimator(). + * + * @param bytes the contents of a glTF 2.0 file (JSON or GLB) + * @param numBytes the number of bytes in "bytes" + * @param instances destination pointer, to be populated by the requested number of instances + * @param numInstances requested number of instances + * @return the primary asset that has ownership over all instances + */ + FilamentAsset* createInstancedAsset(const uint8_t* bytes, uint32_t numBytes, + FilamentInstance** instances, size_t numInstances); + + /** + * Adds a new instance to the asset. + * + * Use this with caution. It is more efficient to pre-allocate a max number of instances, and + * gradually add them to the scene as needed. Instances can also be "recycled" by removing and + * re-adding them to the scene. + * + * NOTE: destroyInstance() does not exist because gltfio favors flat arrays for storage of + * entity lists and instance lists, which would be slow to shift. We also wish to discourage + * create/destroy churn, as noted above. + * + * This cannot be called after FilamentAsset::releaseSourceData(). + * See also AssetLoader::createInstancedAsset(). + */ + FilamentInstance* createInstance(FilamentAsset* asset); + + /** + * Allows clients to enable diagnostic shading on newly-loaded assets. + */ + void enableDiagnostics(bool enable = true); + + /** + * Destroys the given asset, all of its associated Filament objects, and all associated + * FilamentInstance objects. + * + * This destroys entities, components, material instances, vertex buffers, index buffers, + * and textures. This does not necessarily immediately free all source data, since + * texture decoding or GPU uploading might be underway. + */ + void destroyAsset(const FilamentAsset* asset); + + /** + * Gets a weak reference to an array of cached materials, used internally to create material + * instances for assets. + */ + const filament::Material* const* getMaterials() const noexcept; + + /** + * Gets the number of cached materials. + */ + size_t getMaterialsCount() const noexcept; + + utils::NameComponentManager* getNames() const noexcept; + + NodeManager& getNodeManager() noexcept; + + MaterialProvider& getMaterialProvider() noexcept; + + /*! \cond PRIVATE */ +protected: + AssetLoader() noexcept = default; + ~AssetLoader() = default; + +public: + AssetLoader(AssetLoader const&) = delete; + AssetLoader(AssetLoader&&) = delete; + AssetLoader& operator=(AssetLoader const&) = delete; + AssetLoader& operator=(AssetLoader&&) = delete; + /*! \endcond */ +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_ASSETLOADER_H diff --git a/package/ios/libs/filament/include/gltfio/FilamentAsset.h b/package/ios/libs/filament/include/gltfio/FilamentAsset.h new file mode 100644 index 00000000..6408b363 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/FilamentAsset.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_FILAMENTASSET_H +#define GLTFIO_FILAMENTASSET_H + +#include +#include + +#include + +#include +#include + +namespace filament { + class Camera; + class Engine; + class MaterialInstance; + class Scene; +} + +namespace filament::gltfio { + +class Animator; +class FilamentInstance; + +/** + * \class FilamentAsset FilamentAsset.h gltfio/FilamentAsset.h + * \brief Owns a bundle of Filament objects that have been created by AssetLoader. + * + * For usage instructions, see the documentation for AssetLoader. + * + * This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has + * a filament::TransformManager component, and some entities also have \c Name, \c Renderable, + * \c Light, \c Camera, or \c Node components. + * + * In addition to the aforementioned entities, an asset has strong ownership over a list of + * filament::VertexBuffer, filament::IndexBuffer, filament::Texture, + * and, optionally, a simple animation engine (gltfio::Animator). + * + * Clients must use ResourceLoader to create filament::Texture objects, compute tangent quaternions, + * and upload data into vertex buffers and index buffers. + * + * \todo Only the default glTF scene is loaded, other glTF scenes are ignored. + */ +class UTILS_PUBLIC FilamentAsset { +public: + using Entity = utils::Entity; + using SceneMask = NodeManager::SceneMask; + + /** + * Gets the list of entities, one for each glTF node. All of these have a Transform component. + * Some of the returned entities may also have a Renderable component and/or a Light component. + */ + const Entity* getEntities() const noexcept; + + /** + * Gets the number of entities returned by getEntities(). + */ + size_t getEntityCount() const noexcept; + + /** + * Gets the list of entities in the scene representing lights. All of these have a Light component. + */ + const Entity* getLightEntities() const noexcept; + + /** + * Gets the number of entities returned by getLightEntities(). + */ + size_t getLightEntityCount() const noexcept; + + /** + * Gets the list of entities in the asset that have renderable components. + */ + const utils::Entity* getRenderableEntities() const noexcept; + + /** + * Gets the number of entities returned by getRenderableEntities(). + */ + size_t getRenderableEntityCount() const noexcept; + + /** + * Gets the list of entities in the scene representing cameras. All of these have a \c Camera + * component. + * + * Note about aspect ratios: + * gltfio always uses an aspect ratio of 1.0 when setting the projection matrix for perspective + * cameras. gltfio then sets the camera's scaling matrix with the aspect ratio specified in the + * glTF file (if present). + * + * The camera's scaling matrix allows clients to adjust the aspect ratio independently from the + * camera's projection. + * + * To change the aspect ratio of the glTF camera: + * + * camera->setScaling(double4 {1.0 / newAspectRatio, 1.0, 1.0, 1.0}); + * + * @see filament::Camera::setScaling + */ + const Entity* getCameraEntities() const noexcept; + + /** + * Gets the number of entities returned by getCameraEntities(). + */ + size_t getCameraEntityCount() const noexcept; + + /** + * Gets the transform root for the asset, which has no matching glTF node. + * + * This node exists for convenience, allowing users to transform the entire asset. For instanced + * assets, this is a "super root" where each of its children is a root in a particular instance. + * This allows users to transform all instances en masse if they wish to do so. + */ + Entity getRoot() const noexcept; + + /** + * Pops a ready renderable off the queue, or returns 0 if no renderables have become ready. + * + * NOTE: To determine the progress percentage or completion status, please use + * ResourceLoader#asyncGetLoadProgress. To get the number of ready renderables, + * please use popRenderables(). + * + * This method allows clients to progressively add the asset's renderables to the scene as + * textures gradually become ready through asynchronous loading. For example, on every frame + * progressive applications can do something like this: + * + * while (Entity e = popRenderable()) { scene.addEntity(e); } + * + * Progressive reveal is not supported for dynamically added instances. + * + * \see ResourceLoader#asyncBeginLoad + * \see popRenderables() + */ + Entity popRenderable() noexcept; + + /** + * Pops up to "count" ready renderables off the queue, or returns the available number. + * + * The given pointer should either be null or point to memory that can hold up to count + * entities. If the pointer is null, returns the number of available renderables. Otherwise + * returns the number of entities that have been written. + * + * \see ResourceLoader#asyncBeginLoad + */ + size_t popRenderables(Entity* entities, size_t count) noexcept; + + /** Gets resource URIs for all externally-referenced buffers. */ + const char* const* getResourceUris() const noexcept; + + /** Gets the number of resource URIs returned by getResourceUris(). */ + size_t getResourceUriCount() const noexcept; + + /** + * Gets the bounding box computed from the supplied min / max values in glTF accessors. + * + * This does not return a bounding box over all FilamentInstance, it's just a straightforward + * AAAB that can be determined at load time from the asset data. + */ + filament::Aabb getBoundingBox() const noexcept; + + /** Gets the NameComponentManager label for the given entity, if it exists. */ + const char* getName(Entity) const noexcept; + + /** Returns the first entity with the given name, or 0 if none exist. */ + Entity getFirstEntityByName(const char* name) noexcept; + + /** + * Gets a list of entities with the given name. + * + * @param name Null-terminated string to match. + * @param entities Pointer to an array to populate. + * @param maxCount Maximum number of entities to retrieve. + * + * @return If entities is non-null, the number of entities written to the entity pointer. + * Otherwise this returns the number of entities with the given name. + */ + size_t getEntitiesByName(const char* name, Entity* entities, + size_t maxCount) const noexcept; + + /** + * Gets a list of entities whose names start with the given prefix. + * + * @param prefix Null-terminated prefix string to match. + * @param entities Pointer to an array to populate. + * @param maxCount Maximum number of entities to retrieve. + * + * @return If entities is non-null, the number of entities written to the entity pointer. + * Otherwise this returns the number of entities with the given prefix. + */ + size_t getEntitiesByPrefix(const char* prefix, Entity* entities, + size_t maxCount) const noexcept; + + /** Gets the glTF extras string for a specific node, or for the asset, if it exists. */ + const char* getExtras(Entity entity = {}) const noexcept; + + /** + * Gets the morph target name at the given index in the given entity. + */ + const char* getMorphTargetNameAt(Entity entity, size_t targetIndex) const noexcept; + + /** + * Returns the number of morph targets in the given entity. + */ + size_t getMorphTargetCountAt(Entity entity) const noexcept; + + /** + * Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy + * for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it. + */ + Entity getWireframe() noexcept; + + /** + * Returns the Filament engine associated with the AssetLoader that created this asset. + */ + filament::Engine* getEngine() const noexcept; + + /** + * Reclaims CPU-side memory for URI strings, binding lists, and raw animation data. + * + * This should only be called after ResourceLoader::loadResources(). + * If this is an instanced asset, this prevents creation of new instances. + */ + void releaseSourceData() noexcept; + + /** + * Returns a weak reference to the underlying cgltf hierarchy. This becomes invalid after + * calling releaseSourceData(). + */ + const void* getSourceAsset() noexcept; + + /** + * Returns the number of scenes in the asset. + */ + size_t getSceneCount() const noexcept; + + /** + * Returns the name of the given scene. + * + * Returns null if the given scene does not have a name or is out of bounds. + */ + const char* getSceneName(size_t sceneIndex) const noexcept; + + /** + * Adds entities to a Filament scene only if they belong to at least one of the given glTF + * scenes. + * + * This is just a helper that provides an alternative to directly calling scene->addEntities() + * and provides filtering functionality. + */ + void addEntitiesToScene(filament::Scene& targetScene, const Entity* entities, size_t count, + SceneMask sceneFilter) const; + + /** + * Releases ownership of entities and their Filament components. + * + * This makes the client take responsibility for destroying Filament + * components (e.g. Renderable, TransformManager component) as well as + * the underlying entities. + */ + void detachFilamentComponents() noexcept; + + bool areFilamentComponentsDetached() const noexcept; + + /** + * Convenience function to get the first instance, or null if it doesn't exist. + */ + FilamentInstance* getInstance() noexcept { + return getAssetInstanceCount() > 0 ? getAssetInstances()[0] : nullptr; + } + + /*! \cond PRIVATE */ + + FilamentInstance** getAssetInstances() noexcept; + size_t getAssetInstanceCount() const noexcept; + +protected: + FilamentAsset() noexcept = default; + ~FilamentAsset() = default; + +public: + FilamentAsset(FilamentAsset const&) = delete; + FilamentAsset(FilamentAsset&&) = delete; + FilamentAsset& operator=(FilamentAsset const&) = delete; + FilamentAsset& operator=(FilamentAsset&&) = delete; + /*! \endcond */ +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_FILAMENTASSET_H diff --git a/package/ios/libs/filament/include/gltfio/FilamentInstance.h b/package/ios/libs/filament/include/gltfio/FilamentInstance.h new file mode 100644 index 00000000..04199639 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/FilamentInstance.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef GLTFIO_FILAMENTINSTANCE_H +#define GLTFIO_FILAMENTINSTANCE_H + +#include +#include + +#include + +namespace filament { +class MaterialInstance; +} + +namespace filament::gltfio { + +class Animator; +class FilamentAsset; + +/** + * \class FilamentInstance FilamentInstance.h gltfio/FilamentInstance.h + * \brief Provides access to a hierarchy of entities that have been instanced from a glTF asset. + * + * Every entity has a TransformManager component, and some entities also have \c Name or + * \c Renderable components. + * + * \see AssetLoader::createInstancedAsset() + */ +class UTILS_PUBLIC FilamentInstance { +public: + /** + * Gets the owner of this instance. + */ + FilamentAsset const* getAsset() const noexcept; + + /** + * Gets the list of entities in this instance, one for each glTF node. All of these have a + * Transform component. Some of the returned entities may also have a Renderable component or + * Name component. + */ + const utils::Entity* getEntities() const noexcept; + + /** + * Gets the number of entities returned by getEntities(). + */ + size_t getEntityCount() const noexcept; + + /** Gets the transform root for the instance, which has no matching glTF node. */ + utils::Entity getRoot() const noexcept; + + /** + * Applies the given material variant to all primitives in this instance. + * + * Ignored if variantIndex is out of bounds. + */ + void applyMaterialVariant(size_t variantIndex) noexcept; + + /** + * Returns the number of material variants in the asset. + */ + size_t getMaterialVariantCount() const noexcept; + + /** + * Returns the name of the given material variant, or null if it is out of bounds. + */ + const char* getMaterialVariantName(size_t variantIndex) const noexcept; + + /** + * Returns the animation engine for the instance. + * + * Note that an animator can be obtained either from an individual instance, or from the + * originating FilamentAsset. In the latter case, the animation frame is shared amongst all + * instances. If individual control is desired, users must obtain the animator from the + * individual instances. + * + * The animator is owned by the asset and should not be manually deleted. + */ + Animator* getAnimator() noexcept; + + /** + * Gets the number of skins. + */ + size_t getSkinCount() const noexcept; + + /** + * Gets the skin name at skin index. + */ + const char* getSkinNameAt(size_t skinIndex) const noexcept; + + /** + * Gets the number of joints at skin index. + */ + size_t getJointCountAt(size_t skinIndex) const noexcept; + + /** + * Gets joints at skin index. + */ + const utils::Entity* getJointsAt(size_t skinIndex) const noexcept; + + /** + * Attaches the given skin to the given node, which must have an associated mesh with + * BONE_INDICES and BONE_WEIGHTS attributes. + * + * This is a no-op if the given skin index or target is invalid. + */ + void attachSkin(size_t skinIndex, utils::Entity target) noexcept; + + /** + * Detaches the given skin from the given node. + * + * This is a no-op if the given skin index or target is invalid. + */ + void detachSkin(size_t skinIndex, utils::Entity target) noexcept; + + /** + * Gets inverse bind matrices for all joints at the given skin index. + * + * See getJointCountAt for determining the number of matrices returned (i.e. the number of joints). + */ + math::mat4f const* getInverseBindMatricesAt(size_t skinIndex) const; + + /** + * Resets the AABB on all renderables by manually computing the bounding box. + * + * THIS IS ONLY USEFUL FOR MALFORMED ASSETS THAT DO NOT HAVE MIN/MAX SET UP CORRECTLY. + * + * Does not affect the return value of getBoundingBox() on the owning asset. + * Cannot be called after releaseSourceData() on the owning asset. + * Can only be called after loadResources() or asyncBeginLoad(). + */ + void recomputeBoundingBoxes(); + + /** + * Gets the axis-aligned bounding box from the supplied min / max values in glTF accessors. + * + * If recomputeBoundingBoxes() has been called, then this returns the recomputed AABB. + */ + Aabb getBoundingBox() const noexcept; + + /** Gets all material instances. These are already bound to renderables. */ + const MaterialInstance* const* getMaterialInstances() const noexcept; + + /** Gets all material instances (non-const). These are already bound to renderables. */ + MaterialInstance* const* getMaterialInstances() noexcept; + + /** Gets the number of materials returned by getMaterialInstances(). */ + size_t getMaterialInstanceCount() const noexcept; + + /** + * Releases ownership of material instances. + * + * This makes the client take responsibility for destroying MaterialInstance + * objects. The getMaterialInstances query becomes invalid after detachment. + */ + void detachMaterialInstances(); +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_FILAMENTINSTANCE_H diff --git a/package/ios/libs/filament/include/gltfio/MaterialProvider.h b/package/ios/libs/filament/include/gltfio/MaterialProvider.h new file mode 100644 index 00000000..f62d667b --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/MaterialProvider.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_MATERIALPROVIDER_H +#define GLTFIO_MATERIALPROVIDER_H + +#include +#include +#include + +#include + +#include +#include + +namespace filament::gltfio { + +enum class AlphaMode : uint8_t { + OPAQUE, + MASK, + BLEND +}; + +// The following struct gets hashed so all padding bits should be explicit. +// Tell the compiler to emit a warning if it adds any padding. +UTILS_WARNING_PUSH +UTILS_WARNING_ENABLE_PADDED + +/** + * \struct MaterialKey MaterialProvider.h gltfio/MaterialProvider.h + * \brief Small POD structure that specifies the requirements for a glTF material. + * \note This key is processed by MurmurHashFn so please make padding explicit. + */ +struct alignas(4) MaterialKey { + // -- 32 bit boundary -- + bool doubleSided : 1; + bool unlit : 1; + bool hasVertexColors : 1; + bool hasBaseColorTexture : 1; + bool hasNormalTexture : 1; + bool hasOcclusionTexture : 1; + bool hasEmissiveTexture : 1; + bool useSpecularGlossiness : 1; + AlphaMode alphaMode : 4; + bool enableDiagnostics : 4; + union { + struct { + bool hasMetallicRoughnessTexture : 1; + uint8_t metallicRoughnessUV : 7; + }; + struct { + bool hasSpecularGlossinessTexture : 1; + uint8_t specularGlossinessUV : 7; + }; + }; + uint8_t baseColorUV; + // -- 32 bit boundary -- + bool hasClearCoatTexture : 1; + uint8_t clearCoatUV : 7; + bool hasClearCoatRoughnessTexture : 1; + uint8_t clearCoatRoughnessUV : 7; + bool hasClearCoatNormalTexture : 1; + uint8_t clearCoatNormalUV : 7; + bool hasClearCoat : 1; + bool hasTransmission : 1; + bool hasTextureTransforms : 6; + // -- 32 bit boundary -- + uint8_t emissiveUV; + uint8_t aoUV; + uint8_t normalUV; + bool hasTransmissionTexture : 1; + uint8_t transmissionUV : 7; + // -- 32 bit boundary -- + bool hasSheenColorTexture : 1; + uint8_t sheenColorUV : 7; + bool hasSheenRoughnessTexture : 1; + uint8_t sheenRoughnessUV : 7; + bool hasVolumeThicknessTexture : 1; + uint8_t volumeThicknessUV : 7; + bool hasSheen : 1; + bool hasIOR : 1; + bool hasVolume : 1; + uint8_t padding : 5; +}; + +static_assert(sizeof(MaterialKey) == 16, "MaterialKey has unexpected size."); + +UTILS_WARNING_POP + +bool operator==(const MaterialKey& k1, const MaterialKey& k2); + +// Define a mapping from a uv set index in the source asset to one of Filament's uv sets. +enum UvSet : uint8_t { UNUSED, UV0, UV1 }; +constexpr int UvMapSize = 8; +using UvMap = std::array; + +inline uint8_t getNumUvSets(const UvMap& uvmap) { + return std::max({ + uvmap[0], uvmap[1], uvmap[2], uvmap[3], + uvmap[4], uvmap[5], uvmap[6], uvmap[7], + }); +}; + +/** + * \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h + * \brief Interface to a provider of glTF materials (has two implementations). + * + * - The \c JitShaderProvider implementation generates materials at run time (which can be slow) and + * requires the filamat library, but produces streamlined shaders. See createJitShaderProvider(). + * + * - The \c UbershaderProvider implementation uses a small number of pre-built materials with complex + * fragment shaders, but does not require any run time work or usage of filamat. See + * createUbershaderProvider(). + * + * Both implementations of MaterialProvider maintain a small cache of materials which must be + * explicitly freed using destroyMaterials(). These materials are not freed automatically when the + * MaterialProvider is destroyed, which allows clients to take ownership if desired. + * + */ +class UTILS_PUBLIC MaterialProvider { +public: + virtual ~MaterialProvider() {} + + /** + * Creates or fetches a compiled Filament material, then creates an instance from it. + * + * @param config Specifies requirements; might be mutated due to resource constraints. + * @param uvmap Output argument that gets populated with a small table that maps from a glTF uv + * index to a Filament uv index. + * @param label Optional tag that is not a part of the cache key. + * @param extras Optional extras as stringified JSON (not a part of the cache key). + * Does not store the pointer. + */ + virtual MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, + const char* label = "material", const char* extras = nullptr) = 0; + + /** + * Creates or fetches a compiled Filament material corresponding to the given config. + */ + virtual Material* getMaterial(MaterialKey* config, UvMap* uvmap, + const char* label = "material") { return nullptr; } + + /** + * Gets a weak reference to the array of cached materials. + */ + virtual const Material* const* getMaterials() const noexcept = 0; + + /** + * Gets the number of cached materials. + */ + virtual size_t getMaterialsCount() const noexcept = 0; + + /** + * Destroys all cached materials. + * + * This is not called automatically when MaterialProvider is destroyed, which allows + * clients to take ownership of the cache if desired. + */ + virtual void destroyMaterials() = 0; + + /** + * Returns true if the presence of the given vertex attribute is required. + * + * Some types of providers (e.g. ubershader) require dummy attribute values + * if the glTF model does not provide them. + */ + virtual bool needsDummyData(VertexAttribute attrib) const noexcept = 0; +}; + +void constrainMaterial(MaterialKey* key, UvMap* uvmap); + +void processShaderString(std::string* shader, const UvMap& uvmap, + const MaterialKey& config); + +/** + * Creates a material provider that builds materials on the fly, composing GLSL at run time. + * + * @param optimizeShaders Optimizes shaders, but at significant cost to construction time. + * @return New material provider that can build materials at run time. + * + * Requires \c libfilamat to be linked in. Not available in \c libgltfio_core. + * + * @see createUbershaderProvider + */ +UTILS_PUBLIC +MaterialProvider* createJitShaderProvider(Engine* engine, bool optimizeShaders = false); + +/** + * Creates a material provider that loads a small set of pre-built materials. + * + * @return New material provider that can quickly load a material from a cache. + * + * @see createJitShaderProvider + */ +UTILS_PUBLIC +MaterialProvider* createUbershaderProvider(Engine* engine, const void* archive, + size_t archiveByteCount); + +} // namespace filament::gltfio + +#endif // GLTFIO_MATERIALPROVIDER_H diff --git a/package/ios/libs/filament/include/gltfio/NodeManager.h b/package/ios/libs/filament/include/gltfio/NodeManager.h new file mode 100644 index 00000000..04f7bd6d --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/NodeManager.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#ifndef GLTFIO_NODEMANAGER_H +#define GLTFIO_NODEMANAGER_H + +#include + +#include +#include +#include +#include +#include + +namespace utils { +class Entity; +} // namespace utils + +namespace filament::gltfio { + +class FNodeManager; + +/** + * NodeManager is used to add annotate entities with glTF-specific information. + * + * Node components are created by gltfio and exposed to users to allow inspection. + * + * Nodes do not store the glTF hierarchy or names; see TransformManager and NameComponentManager. + */ +class UTILS_PUBLIC NodeManager { +public: + using Instance = utils::EntityInstance; + using Entity = utils::Entity; + using CString = utils::CString; + using SceneMask = utils::bitset32; + + static constexpr size_t MAX_SCENE_COUNT = 32; + + /** + * Returns whether a particular Entity is associated with a component of this NodeManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(Entity e) const noexcept; + + /** + * Gets an Instance representing the node component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the node component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(Entity e) const noexcept; + + /** + * Creates a node component and associates it with the given entity. + * @param entity An Entity to associate a node component with. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(Entity e) was called. + * + * @see destroy() + */ + void create(Entity entity); + + /** + * Destroys this component from the given entity. + * @param e An entity. + * + * @see create() + */ + void destroy(Entity e) noexcept; + + void setMorphTargetNames(Instance ci, utils::FixedCapacityVector names) noexcept; + const utils::FixedCapacityVector& getMorphTargetNames(Instance ci) const noexcept; + + void setExtras(Instance ci, CString extras) noexcept; + const CString& getExtras(Instance ci) const noexcept; + + void setSceneMembership(Instance ci, SceneMask scenes) noexcept; + SceneMask getSceneMembership(Instance ci) const noexcept; + +protected: + NodeManager() noexcept = default; + ~NodeManager() = default; + +public: + NodeManager(NodeManager const&) = delete; + NodeManager(NodeManager&&) = delete; + NodeManager& operator=(NodeManager const&) = delete; + NodeManager& operator=(NodeManager&&) = delete; +}; + +} // namespace filament::gltfio + + +#endif // GLTFIO_NODEMANAGER_H diff --git a/package/ios/libs/filament/include/gltfio/ResourceLoader.h b/package/ios/libs/filament/include/gltfio/ResourceLoader.h new file mode 100644 index 00000000..05c8a56d --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/ResourceLoader.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef GLTFIO_RESOURCELOADER_H +#define GLTFIO_RESOURCELOADER_H + +#include + +#include + +#include + +namespace filament { + class Engine; +} + +namespace filament::gltfio { + +struct FFilamentAsset; +class AssetPool; +class TextureProvider; + +/** + * \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h + * \brief Construction parameters for ResourceLoader. + */ +struct ResourceConfiguration { + //! The engine that the loader should pass to builder objects (e.g. + //! filament::Texture::Builder). + class filament::Engine* engine; + + //! Optional path or URI that points to the base glTF file. This is used solely + //! to resolve relative paths. The string pointer is not retained. + const char* gltfPath; + + //! If true, adjusts skinning weights to sum to 1. Well formed glTF files do not need this, + //! but it is useful for robustness. + bool normalizeSkinningWeights; +}; + +/** + * \class ResourceLoader ResourceLoader.h gltfio/ResourceLoader.h + * \brief Prepares and uploads vertex buffers and textures to the GPU. + * + * For a usage example, see the documentation for AssetLoader. + * + * ResourceLoader must be destroyed on the same thread that calls filament::Renderer::render() + * because it listens to filament::backend::BufferDescriptor callbacks in order to determine when to + * free CPU-side data blobs. + * + * \todo If clients persist their ResourceLoader, Filament textures are currently re-created upon + * subsequent re-loads of the same asset. To fix this, we would need to enable shared ownership + * of Texture objects between ResourceLoader and FilamentAsset. + */ +class UTILS_PUBLIC ResourceLoader { +public: + using BufferDescriptor = filament::backend::BufferDescriptor; + + explicit ResourceLoader(const ResourceConfiguration& config); + ~ResourceLoader(); + + + void setConfiguration(const ResourceConfiguration& config); + + /** + * Feeds the binary content of an external resource into the loader's URI cache. + * + * On some platforms, `ResourceLoader` does not know how to download external resources on its + * own (external resources might come from a filesystem, a database, or the internet) so this + * method allows clients to download external resources and push them to the loader. + * + * Every resource should be passed in before calling #loadResources or #asyncBeginLoad. See + * also FilamentAsset#getResourceUris. + * + * When loading GLB files (as opposed to JSON-based glTF files), clients typically do not + * need to call this method. + */ + void addResourceData(const char* uri, BufferDescriptor&& buffer); + + /** + * Register a plugin that can consume PNG / JPEG content and produce filament::Texture objects. + * + * Destruction of the given provider is the client's responsibility. + */ + void addTextureProvider(const char* mimeType, TextureProvider* provider); + + /** + * Checks if the given resource has already been added to the URI cache. + */ + bool hasResourceData(const char* uri) const; + + /** + * Frees memory by evicting the URI cache that was populated via addResourceData. + * + * This can be called only after a model is fully loaded or after loading has been cancelled. + */ + void evictResourceData(); + + /** + * Loads resources for the given asset from the filesystem or data cache and "finalizes" the + * asset by transforming the vertex data format if necessary, decoding image files, supplying + * tangent data, etc. + * + * Returns false if resources have already been loaded, or if one or more resources could not + * be loaded. + * + * Note: this method is synchronous and blocks until all textures have been decoded. + * For an asynchronous alternative, see #asyncBeginLoad. + */ + bool loadResources(FilamentAsset* asset); + + /** + * Starts an asynchronous resource load. + * + * Returns false if the loading process was unable to start. + * + * This is an alternative to #loadResources and requires periodic calls to #asyncUpdateLoad. + * On multi-threaded systems this creates threads for texture decoding. + */ + bool asyncBeginLoad(FilamentAsset* asset); + + /** + * Gets the status of an asynchronous resource load as a percentage in [0,1]. + */ + float asyncGetLoadProgress() const; + + /** + * Updates an asynchronous load by performing any pending work that must take place + * on the main thread. + * + * Clients must periodically call this until #asyncGetLoadProgress returns 100%. + * After progress reaches 100%, calling this is harmless; it just does nothing. + */ + void asyncUpdateLoad(); + + /** + * Cancels pending decoder jobs, frees all CPU-side texel data, and flushes the Engine. + * + * Calling this is only necessary if the asyncBeginLoad API was used + * and cancellation is required before progress reaches 100%. + */ + void asyncCancelLoad(); + +private: + bool loadResources(FFilamentAsset* asset, bool async); + void normalizeSkinningWeights(FFilamentAsset* asset) const; + struct Impl; + Impl* pImpl; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_RESOURCELOADER_H + diff --git a/package/ios/libs/filament/include/gltfio/TextureProvider.h b/package/ios/libs/filament/include/gltfio/TextureProvider.h new file mode 100644 index 00000000..ff497af2 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/TextureProvider.h @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#ifndef GLTFIO_TEXTUREPROVIDER_H +#define GLTFIO_TEXTUREPROVIDER_H + +#include +#include + +#include +#include + +namespace filament { + class Engine; + class Texture; +} + +namespace filament::gltfio { + +/** + * TextureProvider is an interface that allows clients to implement their own texture decoding + * facility for JPEG, PNG, or KTX2 content. It constructs Filament Texture objects synchronously, + * but populates their miplevels asynchronously. + * + * gltfio calls all public methods from the foreground thread, i.e. the thread that the Filament + * engine was created with. However the implementation may create 0 or more background threads to + * perform decoding work. + * + * The following pseudocode illustrates how this interface could be used, but in practice the only + * client is the gltfio ResourceLoader. + * + * filament::Engine* engine = ...; + * TextureProvider* provider = createStbProvider(engine); + * + * for (auto filename : textureFiles) { + * std::vector buf = readEntireFile(filename); + * Texture* texture = provider->pushTexture(buf.data(), buf.size(), "image/png", 0); + * if (texture == nullptr) { puts(provider->getPushMessage()); exit(1); } + * } + * + * // At this point, the returned textures can be bound to material instances, but none of their + * // miplevel images have been populated yet. + * + * while (provider->getPoppedCount() < provider->getPushedCount()) { + * sleep(200); + * + * // The following call gives the provider an opportunity to reap the results of any + * // background decoder work that has been completed (e.g. by calling Texture::setImage). + * provider->updateQueue(); + * + * // Check for textures that now have all their miplevels initialized. + * while (Texture* texture = provider->popTexture()) { + * printf("%p has all its miplevels ready.\n", texture); + * } + * } + * + * delete provider; + */ +class UTILS_PUBLIC TextureProvider { +public: + using Texture = filament::Texture; + + enum class TextureFlags : uint64_t { + NONE = 0, + sRGB = 1 << 0, + }; + + /** + * Creates a Filament texture and pushes it to the asynchronous decoding queue. + * + * The provider synchronously determines the texture dimensions in order to create a Filament + * texture object, then populates the miplevels asynchronously. + * + * If construction fails, nothing is pushed to the queue and null is returned. The failure + * reason can be obtained with getPushMessage(). The given buffer pointer is not held, so the + * caller can free it immediately. It is also the caller's responsibility to free the returned + * Texture object, but it is only safe to do so after it has been popped from the queue. + */ + virtual Texture* pushTexture(const uint8_t* data, size_t byteCount, + const char* mimeType, TextureFlags flags) = 0; + + /** + * Checks if any texture is ready to be removed from the asynchronous decoding queue, and if so + * pops it off. + * + * Unless an error or cancellation occurred during the decoding process, the returned texture + * should have all its miplevels populated. If the texture is not complete, the reason can be + * obtained with getPopMessage(). + * + * Due to concurrency, textures are not necessarily popped off in the same order they were + * pushed. Returns null if there are no textures that are ready to be popped. + */ + virtual Texture* popTexture() = 0; + + /** + * Polls textures in the queue and uploads mipmap images if any have emerged from the decoder. + * + * This gives the provider an opportunity to call Texture::setImage() on the foreground thread. + * If needed, it can also call Texture::generateMipmaps() here. + * + * Items in the decoding queue can become "poppable" only during this call. + */ + virtual void updateQueue() = 0; + + /** + * Returns a failure message for the most recent call to pushTexture(), or null for success. + * + * Note that this method does not pertain to the decoding process. If decoding fails, clients to + * can pop the incomplete texture off the queue and obtain a failure message using the + * getPopFailure() method. + * + * The returned string is owned by the provider and becomes invalid after the next call to + * pushTexture(). + */ + virtual const char* getPushMessage() const = 0; + + /** + * Returns a failure message for the most recent call to popTexture(), or null for success. + * + * If the most recent call to popTexture() returned null, then no error occurred and this + * returns null. If the most recent call to popTexture() returned a "complete" texture (i.e. + * all miplevels present), then this returns null. This returns non-null only if an error or + * cancellation occurred while decoding the popped texture. + * + * The returned string is owned by the provider and becomes invalid after the next call to + * popTexture(). + */ + virtual const char* getPopMessage() const = 0; + + /** + * Waits for all outstanding decoding jobs to complete. + * + * Clients should call updateQueue() afterwards if they wish to update the push / pop queue. + */ + virtual void waitForCompletion() = 0; + + /** + * Cancels all not-yet-started decoding jobs and waits for all other jobs to complete. + * + * Jobs that have already started cannot be canceled. Textures whose decoding process has + * been cancelled will be made poppable on the subsequent call to updateQueue(). + */ + virtual void cancelDecoding() = 0; + + /** Total number of successful push calls since the provider was created. */ + virtual size_t getPushedCount() const = 0; + + /** Total number of successful pop calls since the provider was created. */ + virtual size_t getPoppedCount() const = 0; + + /** Total number of textures that have become ready-to-pop since the provider was created. */ + virtual size_t getDecodedCount() const = 0; + + virtual ~TextureProvider() = default; +}; + +/** + * Creates a simple decoder based on stb_image that can handle "image/png" and "image/jpeg". + * This works only if your build configuration includes STB. + */ +TextureProvider* createStbProvider(filament::Engine* engine); + +/** + * Creates a decoder that can handle certain types of "image/ktx2" content as specified in + * the KHR_texture_basisu specification. + */ +TextureProvider* createKtx2Provider(filament::Engine* engine); + +} // namespace filament::gltfio + +template<> struct utils::EnableBitMaskOperators + : public std::true_type {}; + +#endif // GLTFIO_TEXTUREPROVIDER_H diff --git a/package/ios/libs/filament/include/gltfio/TrsTransformManager.h b/package/ios/libs/filament/include/gltfio/TrsTransformManager.h new file mode 100644 index 00000000..980457b7 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/TrsTransformManager.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef GLTFIO_TRSTRANSFORMMANAGER_H +#define GLTFIO_TRSTRANSFORMMANAGER_H + +#include + +#include +#include +#include +#include +#include + +using namespace filament::math; + +namespace utils { +class Entity; +} // namespace utils + +namespace filament::gltfio { + +class FTrsTransformManager; + +/** + * TrsTransformManager is used to add entities with glTF-specific trs information. + * + * Trs information here just used for Animation, DON'T use for transform. + */ +class UTILS_PUBLIC TrsTransformManager { +public: + using Instance = utils::EntityInstance; + using Entity = utils::Entity; + + /** + * Returns whether a particular Entity is associated with a component of this TrsTransformManager + * @param e An Entity. + * @return true if this Entity has a component associated with this manager. + */ + bool hasComponent(Entity e) const noexcept; + + /** + * Gets an Instance representing the trs transform component associated with the given Entity. + * @param e An Entity. + * @return An Instance object, which represents the trs transform component associated with the Entity e. + * @note Use Instance::isValid() to make sure the component exists. + * @see hasComponent() + */ + Instance getInstance(Entity e) const noexcept; + + /** + * Creates a trs transform component and associates it with the given entity. + * @param entity An Entity to associate a trs transform component with. + * @param translation The translation to initialize the trs transform component with. + * @param rotation The rotation to initialize the trs transform component with. + * @param scale The scale to initialize the trs transform component with. + * + * If this component already exists on the given entity, it is first destroyed as if + * destroy(Entity e) was called. + * + * @see destroy() + */ + void create(Entity entity); + void create(Entity entity, const float3& translation, const quatf& rotation, + const float3& scale); //!< \overload + + /** + * Destroys this component from the given entity. + * @param e An entity. + * + * @see create() + */ + void destroy(Entity e) noexcept; + + void setTranslation(Instance ci, const float3& translation) noexcept; + const float3& getTranslation(Instance ci) const noexcept; + + void setRotation(Instance ci, const quatf& rotation) noexcept; + const quatf& getRotation(Instance ci) const noexcept; + + void setScale(Instance ci, const float3& scale) noexcept; + const float3& getScale(Instance ci) const noexcept; + + void setTrs(Instance ci, const float3& translation, const quatf& rotation, + const float3& scale) noexcept; + const mat4f getTransform(Instance ci) const noexcept; + +protected: + TrsTransformManager() noexcept = default; + ~TrsTransformManager() = default; + +public: + TrsTransformManager(TrsTransformManager const&) = delete; + TrsTransformManager(TrsTransformManager&&) = delete; + TrsTransformManager& operator=(TrsTransformManager const&) = delete; + TrsTransformManager& operator=(TrsTransformManager&&) = delete; +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_TRSTRANSFORMMANAGER_H diff --git a/package/ios/libs/filament/include/gltfio/materials/uberarchive.h b/package/ios/libs/filament/include/gltfio/materials/uberarchive.h new file mode 100644 index 00000000..b36ddd36 --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/materials/uberarchive.h @@ -0,0 +1,13 @@ +#ifndef UBERARCHIVE_H_ +#define UBERARCHIVE_H_ + +#include + +extern "C" { + extern const uint8_t UBERARCHIVE_PACKAGE[]; + extern int UBERARCHIVE_DEFAULT_OFFSET; + extern int UBERARCHIVE_DEFAULT_SIZE; +} +#define UBERARCHIVE_DEFAULT_DATA (UBERARCHIVE_PACKAGE + UBERARCHIVE_DEFAULT_OFFSET) + +#endif diff --git a/package/ios/libs/filament/include/gltfio/math.h b/package/ios/libs/filament/include/gltfio/math.h new file mode 100644 index 00000000..dfbe0fca --- /dev/null +++ b/package/ios/libs/filament/include/gltfio/math.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef GLTFIO_MATH_H +#define GLTFIO_MATH_H + +#include +#include +#include +#include +#include + +#include + +namespace filament::gltfio { + +template +UTILS_PUBLIC T cubicSpline(const T& vert0, const T& tang0, const T& vert1, const T& tang1, float t) { + float tt = t * t, ttt = tt * t; + float s2 = -2 * ttt + 3 * tt, s3 = ttt - tt; + float s0 = 1 - s2, s1 = s3 - tt + t; + T p0 = vert0; + T m0 = tang0; + T p1 = vert1; + T m1 = tang1; + return s0 * p0 + s1 * m0 * t + s2 * p1 + s3 * m1 * t; +} + +UTILS_PUBLIC inline void decomposeMatrix(const filament::math::mat4f& mat, filament::math::float3* translation, + filament::math::quatf* rotation, filament::math::float3* scale) { + using namespace filament::math; + + // Extract translation. + *translation = mat[3].xyz; + + // Extract upper-left for determinant computation. + const float a = mat[0][0]; + const float b = mat[0][1]; + const float c = mat[0][2]; + const float d = mat[1][0]; + const float e = mat[1][1]; + const float f = mat[1][2]; + const float g = mat[2][0]; + const float h = mat[2][1]; + const float i = mat[2][2]; + const float A = e * i - f * h; + const float B = f * g - d * i; + const float C = d * h - e * g; + + // Extract scale. + const float det(a * A + b * B + c * C); + float scalex = length(float3({a, b, c})); + float scaley = length(float3({d, e, f})); + float scalez = length(float3({g, h, i})); + float3 s = { scalex, scaley, scalez }; + if (det < 0) { + s = -s; + } + *scale = s; + + // Remove scale from the matrix if it is not close to zero. + mat4f clone = mat; + if (std::abs(det) > std::numeric_limits::epsilon()) { + clone[0] /= s.x; + clone[1] /= s.y; + clone[2] /= s.z; + // Extract rotation + *rotation = clone.toQuaternion(); + } else { + // Set to identity if close to zero + *rotation = quatf(1.0f); + } +} + +UTILS_PUBLIC inline filament::math::mat4f composeMatrix(const filament::math::float3& translation, + const filament::math::quatf& rotation, const filament::math::float3& scale) { + float tx = translation[0]; + float ty = translation[1]; + float tz = translation[2]; + float qx = rotation[0]; + float qy = rotation[1]; + float qz = rotation[2]; + float qw = rotation[3]; + float sx = scale[0]; + float sy = scale[1]; + float sz = scale[2]; + return filament::math::mat4f( + (1 - 2 * qy*qy - 2 * qz*qz) * sx, + (2 * qx*qy + 2 * qz*qw) * sx, + (2 * qx*qz - 2 * qy*qw) * sx, + 0.f, + (2 * qx*qy - 2 * qz*qw) * sy, + (1 - 2 * qx*qx - 2 * qz*qz) * sy, + (2 * qy*qz + 2 * qx*qw) * sy, + 0.f, + (2 * qx*qz + 2 * qy*qw) * sz, + (2 * qy*qz - 2 * qx*qw) * sz, + (1 - 2 * qx*qx - 2 * qy*qy) * sz, + 0.f, tx, ty, tz, 1.f); +} + +inline filament::math::mat3f matrixFromUvTransform(const float offset[2], float rotation, + const float scale[2]) { + float tx = offset[0]; + float ty = offset[1]; + float sx = scale[0]; + float sy = scale[1]; + float c = cos(rotation); + float s = sin(rotation); + return filament::math::mat3f(sx * c, sx * s, tx, -sy * s, sy * c, ty, 0.0f, 0.0f, 1.0f); +}; + +} // namespace filament::gltfio + +#endif // GLTFIO_MATH_H diff --git a/package/ios/libs/filament/include/ibl/Cubemap.h b/package/ios/libs/filament/include/ibl/Cubemap.h new file mode 100644 index 00000000..2186bdb0 --- /dev/null +++ b/package/ios/libs/filament/include/ibl/Cubemap.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAP_H +#define IBL_CUBEMAP_H + +#include + +#include + +#include +#include +#include + +#include + +namespace filament { +namespace ibl { + +/** + * Generic cubemap class. It handles writing / reading into the 6 faces of a cubemap. + * + * Seamless trilinear filtering is handled. + * + * This class doesn't own the face data, it's just a "view" on the 6 images. + * + * @see CubemapUtils + * + */ +class UTILS_PUBLIC Cubemap { +public: + + /** + * Initialize the cubemap with a given size, but no face is set and no memory is allocated. + * + * Usually Cubemaps are created using CubemapUtils. + * + * @see CubemapUtils + */ + explicit Cubemap(size_t dim); + + Cubemap(Cubemap&&) = default; + Cubemap& operator=(Cubemap&&) = default; + + ~Cubemap(); + + + enum class Face : uint8_t { + PX = 0, // left +----+ + NX, // right | PY | + PY, // bottom +----+----+----+----+ + NY, // top | NX | PZ | PX | NZ | + PZ, // back +----+----+----+----+ + NZ // front | NY | + // +----+ + }; + + using Texel = filament::math::float3; + + + //! releases all images and reset the cubemap size + void resetDimensions(size_t dim); + + //! assigns an image to a face. + void setImageForFace(Face face, const Image& image); + + //! retrieves the image attached to a face + inline const Image& getImageForFace(Face face) const; + + //! retrieves the image attached to a face + inline Image& getImageForFace(Face face); + + //! computes the center of a pixel at coordinate x, y + static inline filament::math::float2 center(size_t x, size_t y); + + //! computes a direction vector from a face and a location of the center of pixel in an Image + inline filament::math::float3 getDirectionFor(Face face, size_t x, size_t y) const; + + //! computes a direction vector from a face and a location in pixel in an Image + inline filament::math::float3 getDirectionFor(Face face, float x, float y) const; + + //! samples the cubemap at the given direction using nearest neighbor filtering + inline Texel const& sampleAt(const filament::math::float3& direction) const; + + //! samples the cubemap at the given direction using bilinear filtering + inline Texel filterAt(const filament::math::float3& direction) const; + + //! samples an image at the given location in pixel using bilinear filtering + static Texel filterAt(const Image& image, float x, float y); + static Texel filterAtCenter(const Image& image, size_t x, size_t y); + + //! samples two cubemaps in a given direction and lerps the result by a given lerp factor + static Texel trilinearFilterAt(const Cubemap& c0, const Cubemap& c1, float lerp, + const filament::math::float3& direction); + + //! reads a texel at a given address + inline static const Texel& sampleAt(void const* data) { + return *static_cast(data); + } + + //! writes a texel at a given address + inline static void writeAt(void* data, const Texel& texel) { + *static_cast(data) = texel; + } + + //! returns the size of the cubemap in pixels + size_t getDimensions() const; + + /** + * Prepares a cubemap for seamless access to its faces. + * + * @warning All faces of the cubemap must be backed-up by the same Image, and must already + * be spaced by 2 lines/rows. + */ + void makeSeamless(); + + struct Address { + Face face; + float s = 0; + float t = 0; + }; + + //! returns the face and texture coordinates of the given direction + static Address getAddressFor(const filament::math::float3& direction); + +private: + size_t mDimensions = 0; + float mScale = 1; + float mUpperBound = 0; + Image mFaces[6]; +}; + +// ------------------------------------------------------------------------------------------------ + +inline const Image& Cubemap::getImageForFace(Face face) const { + return mFaces[int(face)]; +} + +inline Image& Cubemap::getImageForFace(Face face) { + return mFaces[int(face)]; +} + +inline filament::math::float2 Cubemap::center(size_t x, size_t y) { + return { x + 0.5f, y + 0.5f }; +} + +inline filament::math::float3 Cubemap::getDirectionFor(Face face, size_t x, size_t y) const { + return getDirectionFor(face, x + 0.5f, y + 0.5f); +} + +inline filament::math::float3 Cubemap::getDirectionFor(Face face, float x, float y) const { + // map [0, dim] to [-1,1] with (-1,-1) at bottom left + float cx = (x * mScale) - 1; + float cy = 1 - (y * mScale); + + filament::math::float3 dir; + const float l = std::sqrt(cx * cx + cy * cy + 1); + switch (face) { + case Face::PX: dir = { 1, cy, -cx }; break; + case Face::NX: dir = { -1, cy, cx }; break; + case Face::PY: dir = { cx, 1, -cy }; break; + case Face::NY: dir = { cx, -1, cy }; break; + case Face::PZ: dir = { cx, cy, 1 }; break; + case Face::NZ: dir = { -cx, cy, -1 }; break; + } + return dir * (1 / l); +} + +inline Cubemap::Texel const& Cubemap::sampleAt(const filament::math::float3& direction) const { + Cubemap::Address addr(getAddressFor(direction)); + const size_t x = std::min(size_t(addr.s * mDimensions), mDimensions - 1); + const size_t y = std::min(size_t(addr.t * mDimensions), mDimensions - 1); + return sampleAt(getImageForFace(addr.face).getPixelRef(x, y)); +} + +inline Cubemap::Texel Cubemap::filterAt(const filament::math::float3& direction) const { + Cubemap::Address addr(getAddressFor(direction)); + addr.s = std::min(addr.s * mDimensions, mUpperBound); + addr.t = std::min(addr.t * mDimensions, mUpperBound); + return filterAt(getImageForFace(addr.face), addr.s, addr.t); +} + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAP_H */ diff --git a/package/ios/libs/filament/include/ibl/CubemapIBL.h b/package/ios/libs/filament/include/ibl/CubemapIBL.h new file mode 100644 index 00000000..925e27c0 --- /dev/null +++ b/package/ios/libs/filament/include/ibl/CubemapIBL.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAPIBL_H +#define IBL_CUBEMAPIBL_H + +#include + +#include +#include + +#include + +#include +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class Cubemap; +class Image; + +/** + * Generates cubemaps for the IBL. + */ +class UTILS_PUBLIC CubemapIBL { +public: + typedef void (*Progress)(size_t, float, void*); + + /** + * Computes a roughness LOD using prefiltered importance sampling GGX + * + * @param dst the destination cubemap + * @param levels a list of prefiltered lods of the source environment + * @param linearRoughness roughness + * @param maxNumSamples number of samples for importance sampling + * @param updater a callback for the caller to track progress + */ + static void roughnessFilter( + utils::JobSystem& js, Cubemap& dst, const utils::Slice& levels, + float linearRoughness, size_t maxNumSamples, math::float3 mirror, bool prefilter, + Progress updater = nullptr, void* userdata = nullptr); + + static void roughnessFilter( + utils::JobSystem& js, Cubemap& dst, const std::vector& levels, + float linearRoughness, size_t maxNumSamples, math::float3 mirror, bool prefilter, + Progress updater = nullptr, void* userdata = nullptr); + + //! Computes the "DFG" term of the "split-sum" approximation and stores it in a 2D image + static void DFG(utils::JobSystem& js, Image& dst, bool multiscatter, bool cloth); + + /** + * Computes the diffuse irradiance using prefiltered importance sampling GGX + * + * @note Usually this is done using spherical harmonics instead. + * + * @param dst the destination cubemap + * @param levels a list of prefiltered lods of the source environment + * @param maxNumSamples number of samples for importance sampling + * @param updater a callback for the caller to track progress + * + * @see CubemapSH + */ + static void diffuseIrradiance(utils::JobSystem& js, Cubemap& dst, const std::vector& levels, + size_t maxNumSamples = 1024, Progress updater = nullptr, void* userdata = nullptr); + + // for debugging. ignore. + static void brdf(utils::JobSystem& js, Cubemap& dst, float linearRoughness); +}; + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAPIBL_H */ diff --git a/package/ios/libs/filament/include/ibl/CubemapSH.h b/package/ios/libs/filament/include/ibl/CubemapSH.h new file mode 100644 index 00000000..b9297c74 --- /dev/null +++ b/package/ios/libs/filament/include/ibl/CubemapSH.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAPSH_H +#define IBL_CUBEMAPSH_H + + +#include + +#include +#include + +#include +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class Cubemap; + +/** + * Computes spherical harmonics + */ +class UTILS_PUBLIC CubemapSH { +public: + /** + * Spherical Harmonics decomposition of the given cubemap + * Optionally calculates irradiance by convolving with truncated cos. + */ + static std::unique_ptr computeSH( + utils::JobSystem& js, const Cubemap& cm, size_t numBands, bool irradiance); + + /** + * Render given spherical harmonics into a cubemap + */ + static void renderSH(utils::JobSystem& js, Cubemap& cm, + const std::unique_ptr& sh, size_t numBands); + + static void windowSH(std::unique_ptr& sh, size_t numBands, float cutoff); + + /** + * Compute spherical harmonics of the irradiance of the given cubemap. + * The SH basis are pre-scaled for easier rendering by the shader. The resulting coefficients + * are not spherical harmonics (as they're scalled by various factors). In particular they + * cannot be rendered with renderSH() above. Instead use renderPreScaledSH3Bands() which + * is exactly the code ran by our shader. + */ + static void preprocessSHForShader(std::unique_ptr& sh); + + /** + * Render pre-scaled irrandiance SH + */ + static void renderPreScaledSH3Bands(utils::JobSystem& js, Cubemap& cm, + const std::unique_ptr& sh); + + static constexpr size_t getShIndex(ssize_t m, size_t l) { + return SHindex(m, l); + } + +private: + class float5 { + float v[5]; + public: + float5() = default; + constexpr float5(float a, float b, float c, float d, float e) : v{ a, b, c, d, e } {} + constexpr float operator[](size_t i) const { return v[i]; } + float& operator[](size_t i) { return v[i]; } + }; + + static inline const float5 multiply(const float5 M[5], float5 x) noexcept { + return float5{ + M[0][0] * x[0] + M[1][0] * x[1] + M[2][0] * x[2] + M[3][0] * x[3] + M[4][0] * x[4], + M[0][1] * x[0] + M[1][1] * x[1] + M[2][1] * x[2] + M[3][1] * x[3] + M[4][1] * x[4], + M[0][2] * x[0] + M[1][2] * x[1] + M[2][2] * x[2] + M[3][2] * x[3] + M[4][2] * x[4], + M[0][3] * x[0] + M[1][3] * x[1] + M[2][3] * x[2] + M[3][3] * x[3] + M[4][3] * x[4], + M[0][4] * x[0] + M[1][4] * x[1] + M[2][4] * x[2] + M[3][4] * x[3] + M[4][4] * x[4] + }; + }; + + + static inline constexpr size_t SHindex(ssize_t m, size_t l) { + return l * (l + 1) + m; + } + + static void computeShBasis(float* SHb, size_t numBands, const math::float3& s); + + static float Kml(ssize_t m, size_t l); + + static std::vector Ki(size_t numBands); + + static constexpr float computeTruncatedCosSh(size_t l); + + static float sincWindow(size_t l, float w); + + static math::float3 rotateShericalHarmonicBand1(math::float3 band1, math::mat3f const& M); + + static float5 rotateShericalHarmonicBand2(float5 const& band2, math::mat3f const& M); + + // debugging only... + static float Legendre(ssize_t l, ssize_t m, float x); + static float TSH(int l, int m, const math::float3& d); + static void printShBase(std::ostream& out, int l, int m); +}; + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAPSH_H */ diff --git a/package/ios/libs/filament/include/ibl/CubemapUtils.h b/package/ios/libs/filament/include/ibl/CubemapUtils.h new file mode 100644 index 00000000..3b4a3154 --- /dev/null +++ b/package/ios/libs/filament/include/ibl/CubemapUtils.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_CUBEMAP_UTILS_H +#define IBL_CUBEMAP_UTILS_H + +#include +#include + +#include + +#include + +namespace utils { +class JobSystem; +} // namespace utils + +namespace filament { +namespace ibl { + +class CubemapIBL; + +/** + * Create and convert Cubemap formats + */ +class UTILS_PUBLIC CubemapUtils { +public: + //! Creates a cubemap object and its backing Image + static Cubemap create(Image& image, size_t dim, bool horizontal = true); + + struct EmptyState { + }; + + template + using ScanlineProc = std::function< + void(STATE& state, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t width)>; + + template + using ReduceProc = std::function; + + //! process the cubemap using multithreading + template + static void process(Cubemap& cm, + utils::JobSystem& js, + ScanlineProc proc, + ReduceProc reduce = [](STATE&) {}, + const STATE& prototype = STATE()); + + //! process the cubemap + template + static void processSingleThreaded(Cubemap& cm, + utils::JobSystem& js, + ScanlineProc proc, + ReduceProc reduce = [](STATE&) {}, + const STATE& prototype = STATE()); + + //! clamps image to acceptable range + static void clamp(Image& src); + + static void highlight(Image& src); + + //! Downsamples a cubemap by helf in x and y using a box filter + static void downsampleCubemapLevelBoxFilter(utils::JobSystem& js, Cubemap& dst, const Cubemap& src); + + //! Return the name of a face (suitable for a file name) + static const char* getFaceName(Cubemap::Face face); + + //! computes the solid angle of a pixel of a face of a cubemap + static float solidAngle(size_t dim, size_t u, size_t v); + + //! Sets a Cubemap faces from a cross image + static void setAllFacesFromCross(Cubemap& cm, const Image& image); + +private: + + //move these into cmgen? + static void setFaceFromCross(Cubemap& cm, Cubemap::Face face, const Image& image); + static Image createCubemapImage(size_t dim, bool horizontal = true); + +#ifndef FILAMENT_IBL_LITE + +public: + + //! Converts horizontal or vertical cross Image to a Cubemap + static void crossToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src); + + //! Converts equirectangular Image to a Cubemap + static void equirectangularToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src); + + //! Converts a Cubemap to an equirectangular Image + static void cubemapToEquirectangular(utils::JobSystem& js, Image& dst, const Cubemap& src); + + //! Converts a Cubemap to an octahedron + static void cubemapToOctahedron(utils::JobSystem& js, Image& dst, const Cubemap& src); + + //! mirror the cubemap in the horizontal direction + static void mirrorCubemap(utils::JobSystem& js, Cubemap& dst, const Cubemap& src); + + //! generates a UV grid in the cubemap -- useful for debugging. + static void generateUVGrid(utils::JobSystem& js, Cubemap& cml, size_t gridFrequencyX, size_t gridFrequencyY); + +#endif + + friend class CubemapIBL; +}; + + +} // namespace ibl +} // namespace filament + +#endif /* IBL_CUBEMAP_UTILS_H */ diff --git a/package/ios/libs/filament/include/ibl/Image.h b/package/ios/libs/filament/include/ibl/Image.h new file mode 100644 index 00000000..1ebaa62b --- /dev/null +++ b/package/ios/libs/filament/include/ibl/Image.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_IMAGE_H +#define IBL_IMAGE_H + +#include +#include +#include + +#include + +#include + +namespace filament { +namespace ibl { + +class UTILS_PUBLIC Image { +public: + Image(); + Image(size_t w, size_t h, size_t stride = 0); + + void reset(); + + void set(Image const& image); + + void subset(Image const& image, size_t x, size_t y, size_t w, size_t h); + + bool isValid() const { return mData != nullptr; } + + size_t getWidth() const { return mWidth; } + + size_t getStride() const { return mBpr / getBytesPerPixel(); } + + size_t getHeight() const { return mHeight; } + + size_t getBytesPerRow() const { return mBpr; } + + size_t getBytesPerPixel() const { return sizeof(math::float3); } + + void* getData() const { return mData; } + + size_t getSize() const { return mBpr * mHeight; } + + void* getPixelRef(size_t x, size_t y) const; + + std::unique_ptr detach() { return std::move(mOwnedData); } + +private: + size_t mBpr = 0; + size_t mWidth = 0; + size_t mHeight = 0; + std::unique_ptr mOwnedData; + void* mData = nullptr; +}; + +inline void* Image::getPixelRef(size_t x, size_t y) const { + return static_cast(mData) + y * getBytesPerRow() + x * getBytesPerPixel(); +} + +} // namespace ibl +} // namespace filament + +#endif /* IBL_IMAGE_H */ diff --git a/package/ios/libs/filament/include/ibl/utilities.h b/package/ios/libs/filament/include/ibl/utilities.h new file mode 100644 index 00000000..6d40cc03 --- /dev/null +++ b/package/ios/libs/filament/include/ibl/utilities.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef IBL_UTILITIES_H +#define IBL_UTILITIES_H + +#include + +#include +#include + +namespace filament { +namespace ibl { + +template +static inline constexpr T sq(T x) { + return x * x; +} + +template +static inline constexpr T log4(T x) { + // log2(x)/log2(4) + // log2(x)/2 + return std::log2(x) * T(0.5); +} + +inline bool isPOT(size_t x) { + return !(x & (x - 1)); +} + +inline filament::math::float2 hammersley(uint32_t i, float iN) { + constexpr float tof = 0.5f / 0x80000000U; + uint32_t bits = i; + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return { i * iN, bits * tof }; +} + +} // namespace ibl +} // namespace filament +#endif /* IBL_UTILITIES_H */ diff --git a/package/ios/libs/filament/include/image/ColorTransform.h b/package/ios/libs/filament/include/image/ColorTransform.h new file mode 100644 index 00000000..f5f8f195 --- /dev/null +++ b/package/ios/libs/filament/include/image/ColorTransform.h @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_COLORTRANSFORM_H_ +#define IMAGE_COLORTRANSFORM_H_ + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace image { + +template +uint32_t linearToRGB_10_11_11_REV(const T& linear) { + using fp11 = filament::math::fp<0, 5, 6>; + using fp10 = filament::math::fp<0, 5, 5>; + // the max value for a RGB_11_11_10 is {65024, 65024, 64512} : (2 - 2^-M) * 2^(E-1) + // we clamp to the min of that + fp11 r = fp11::fromf(std::min(64512.0f, linear[0])); + fp11 g = fp11::fromf(std::min(64512.0f, linear[1])); + fp10 b = fp10::fromf(std::min(64512.0f, linear[2])); + uint32_t ir = r.bits & 0x7FF; + uint32_t ig = g.bits & 0x7FF; + uint32_t ib = b.bits & 0x3FF; + return (ib << 22) | (ig << 11) | ir; +} + +template +inline filament::math::float4 linearToRGBM(const T& linear) { + using filament::math::float4; + + float4 RGBM(linear[0], linear[1], linear[2], 1.0f); + + // Linear to gamma space + RGBM.rgb = sqrt(RGBM.rgb); + // Set the range + RGBM.rgb /= 16.0f; + + float maxComponent = std::max(std::max(RGBM.r, RGBM.g), std::max(RGBM.b, 1e-6f)); + // Don't let M go below 1 in the [0..16] range + RGBM.a = filament::math::clamp(maxComponent, 1.0f / 16.0f, 1.0f); + RGBM.a = std::ceil(RGBM.a * 255.0f) / 255.0f; + + RGBM.rgb = saturate(RGBM.rgb / RGBM.a); + + return RGBM; +} + +template +inline filament::math::float3 RGBMtoLinear(const T& rgbm) { + using filament::math::float3; + + float3 linear(rgbm[0], rgbm[1], rgbm[2]); + linear *= rgbm.a * 16.0f; + // Gamma to linear space + return linear * linear; +} + +template +inline filament::math::float3 linearTosRGB(const T& linear) { + using filament::math::float3; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 1 / 2.4f; + float3 sRGB; + for (size_t i=0 ; i<3 ; i++) { + if (linear[i] <= 0.0031308f) { + sRGB[i] = linear[i] * 12.92f; + } else { + sRGB[i] = a1 * std::pow(linear[i], p) - a; + } + } + return sRGB; +} + +inline float linearTosRGB(float linear) { + if (linear <= 0.0031308f) { + return linear * 12.92f; + } else { + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 1 / 2.4f; + return a1 * std::pow(linear, p) - a; + } +} + +template +T sRGBToLinear(const T& sRGB); + +template<> +inline filament::math::float3 sRGBToLinear(const filament::math::float3& sRGB) { + using filament::math::float3; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 2.4f; + float3 linear; + for (size_t i=0 ; i<3 ; i++) { + if (sRGB[i] <= 0.04045f) { + linear[i] = sRGB[i] * (1.0f / 12.92f); + } else { + linear[i] = std::pow((sRGB[i] + a) / a1, p); + } + } + return linear; +} + +template<> +inline filament::math::float4 sRGBToLinear(const filament::math::float4& sRGB) { + using filament::math::float4; + constexpr float a = 0.055f; + constexpr float a1 = 1.055f; + constexpr float p = 2.4f; + float4 linear; + for (size_t i=0 ; i<3 ; i++) { + if (sRGB[i] <= 0.04045f) { + linear[i] = sRGB[i] * (1.0f / 12.92f); + } else { + linear[i] = std::pow((sRGB[i] + a) / a1, p); + } + } + linear[3] = sRGB[3]; + return linear; +} + +template +T linearToSRGB(const T& color); + +template<> +inline filament::math::float3 linearToSRGB(const filament::math::float3& color) { + using filament::math::float3; + float3 sRGBColor{color}; + UTILS_NOUNROLL + for (size_t i = 0; i < sRGBColor.size(); i++) { + sRGBColor[i] = (sRGBColor[i] <= 0.0031308f) ? + sRGBColor[i] * 12.92f : (powf(sRGBColor[i], 1.0f / 2.4f) * 1.055f) - 0.055f; + } + return sRGBColor; +} + +// Creates a N-channel sRGB image from a linear floating-point image. +// The source image can have more than N channels, but only the first 3 are converted to sRGB. +template +std::unique_ptr fromLinearTosRGB(const LinearImage& image) { + const size_t w = image.getWidth(); + const size_t h = image.getHeight(); + const size_t nchan = image.getChannels(); + assert(nchan >= N); + std::unique_ptr dst(new uint8_t[w * h * N * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, p += nchan, d += N) { + for (int n = 0; n < N; n++) { + float source = n < 3 ? linearTosRGB(p[n]) : p[n]; + float target = filament::math::saturate(source) * std::numeric_limits::max() + 0.5f; + d[n] = T(target); + } + } + } + return dst; +} + +// Creates a N-channel RGB u8 image from a f32 image. +template +std::unique_ptr fromLinearToRGB(const LinearImage& image) { + size_t w = image.getWidth(); + size_t h = image.getHeight(); + size_t channels = image.getChannels(); + assert(channels >= N); + std::unique_ptr dst(new uint8_t[w * h * N * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, p += channels, d += N) { + for (int n = 0; n < N; n++) { + float target = filament::math::saturate(p[n]) * std::numeric_limits::max() + 0.5f; + d[n] = T(target); + } + } + } + return dst; +} + +// Creates a 4-channel RGBM u8 image from a f32 image. +// The source image can have three or more channels, but only the first three are honored. +template +std::unique_ptr fromLinearToRGBM(const LinearImage& image) { + using namespace filament::math; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + UTILS_UNUSED_IN_RELEASE size_t channels = image.getChannels(); + assert(channels >= 3); + std::unique_ptr dst(new uint8_t[w * h * 4 * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + for (size_t x = 0; x < w; ++x, d += 4) { + auto src = image.get((uint32_t) x, (uint32_t) y); + float4 l(linearToRGBM(*src) * std::numeric_limits::max() + 0.5f); + for (size_t i = 0; i < 4; i++) { + d[i] = T(l[i]); + } + } + } + return dst; +} + +// Creates a 3-channel RGB_10_11_11_REV image from a f32 image. +// The source image can have three or more channels, but only the first three are honored. +inline std::unique_ptr fromLinearToRGB_10_11_11_REV(const LinearImage& image) { + using namespace filament::math; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + UTILS_UNUSED_IN_RELEASE size_t channels = image.getChannels(); + assert(channels >= 3); + std::unique_ptr dst(new uint8_t[w * h * sizeof(uint32_t)]); + uint8_t* d = dst.get(); + for (size_t y = 0; y < h; ++y) { + for (size_t x = 0; x < w; ++x, d += sizeof(uint32_t)) { + auto src = image.get((uint32_t)x, (uint32_t)y); + uint32_t v = linearToRGB_10_11_11_REV(*src); + *reinterpret_cast(d) = v; + } + } + return dst; +} + +// Creates a packed single-channel integer-based image from a floating-point image. +// For example if T is uint8_t, then this performs a transformation from [0,1] to [0,255]. +template +std::unique_ptr fromLinearToGrayscale(const LinearImage& image) { + const size_t w = image.getWidth(); + const size_t h = image.getHeight(); + assert(image.getChannels() == 1); + std::unique_ptr dst(new uint8_t[w * h * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float const* p = image.getPixelRef(0, y); + for (size_t x = 0; x < w; ++x, ++p, ++d) { + const float gray = filament::math::saturate(*p) * std::numeric_limits::max() + 0.5f; + d[0] = T(gray); + } + } + return dst; +} + +// Constructs a 3-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// The "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, + const uint8_t* src, PROCESS proc, TRANSFORM transform) { + LinearImage result((uint32_t) w, (uint32_t) h, 3); + auto d = result.get< filament::math::float3>(); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 3) { + filament::math::float3 sRGB(proc(p[0]), proc(p[1]), proc(p[2])); + sRGB /= std::numeric_limits::max(); + *d++ = transform(sRGB); + } + } + return result; +} + +// Constructs a 3-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// The "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, + const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { + return toLinear(w, h, bpr, src.get(), proc, transform); +} + +// Constructs a 4-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// the "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, + const uint8_t* src, PROCESS proc, TRANSFORM transform) { + LinearImage result((uint32_t) w, (uint32_t) h, 4); + auto d = result.get< filament::math::float4>(); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 4) { + filament::math::float4 sRGB(proc(p[0]), proc(p[1]), proc(p[2]), proc(p[3])); + sRGB /= std::numeric_limits::max(); + *d++ = transform(sRGB); + } + } + return result; +} + +// Constructs a 4-channel LinearImage from an untyped data blob. +// The "proc" lambda converts a single color component into a float. +// the "transform" lambda performs an arbitrary float-to-float transformation. +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, + const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { + return toLinearWithAlpha(w, h, bpr, src.get(), proc, transform); +} + +// Constructs a 3-channel LinearImage from RGBM data. +inline LinearImage toLinearFromRGBM( filament::math::float4 const* src, uint32_t w, uint32_t h) { + LinearImage result(w, h, 3); + auto dst = result.get< filament::math::float3>(); + for (uint32_t row = 0; row < h; ++row) { + for (uint32_t col = 0; col < w; ++col, ++src, ++dst) { + *dst = RGBMtoLinear(*src); + } + } + return result; +} + +inline LinearImage fromLinearToRGBM(const LinearImage& image) { + assert(image.getChannels() == 3); + const uint32_t w = image.getWidth(), h = image.getHeight(); + LinearImage result(w, h, 4); + auto src = image.get< filament::math::float3>(); + auto dst = result.get< filament::math::float4>(); + for (uint32_t row = 0; row < h; ++row) { + for (uint32_t col = 0; col < w; ++col, ++src, ++dst) { + *dst = linearToRGBM(*src); + } + } + return result; +} + +template +static LinearImage toLinearWithAlpha(size_t w, size_t h, size_t bpr, const uint8_t* src) { + LinearImage result(w, h, 4); + filament::math::float4* d = reinterpret_cast(result.getPixelRef(0, 0)); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 4) { + filament::math::float3 sRGB(p[0], p[1], p[2]); + sRGB /= std::numeric_limits::max(); + *d++ = filament::math::float4(sRGBToLinear(sRGB), 1.0f); + } + } + return result; +} + +template +static LinearImage toLinear(size_t w, size_t h, size_t bpr, const uint8_t* src) { + LinearImage result(w, h, 3); + filament::math::float3* d = reinterpret_cast(result.getPixelRef(0, 0)); + for (size_t y = 0; y < h; ++y) { + T const* p = reinterpret_cast(src + y * bpr); + for (size_t x = 0; x < w; ++x, p += 3) { + filament::math::float3 sRGB(p[0], p[1], p[2]); + sRGB /= std::numeric_limits::max(); + *d++ = sRGBToLinear(sRGB); + } + } + return result; +} + +} // namespace Image + +#endif // IMAGE_COLORTRANSFORM_H_ diff --git a/package/ios/libs/filament/include/image/ImageOps.h b/package/ios/libs/filament/include/image/ImageOps.h new file mode 100644 index 00000000..50adc90e --- /dev/null +++ b/package/ios/libs/filament/include/image/ImageOps.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_IMAGEOPS_H +#define IMAGE_IMAGEOPS_H + +#include + +#include + +#include +#include + +namespace image { + +// Concatenates images horizontally to create a filmstrip atlas, similar to numpy's hstack. +UTILS_PUBLIC LinearImage horizontalStack(std::initializer_list images); +UTILS_PUBLIC LinearImage horizontalStack(LinearImage const* img, size_t count); + +// Concatenates images vertically to create a filmstrip atlas, similar to numpy's vstack. +UTILS_PUBLIC LinearImage verticalStack(std::initializer_list images); +UTILS_PUBLIC LinearImage verticalStack(LinearImage const* img, size_t count); + +// Horizontally or vertically mirror the given image. +UTILS_PUBLIC LinearImage horizontalFlip(const LinearImage& image); +UTILS_PUBLIC LinearImage verticalFlip(const LinearImage& image); + +// Transforms normals (components live in [-1,+1]) into colors (components live in [0,+1]). +UTILS_PUBLIC LinearImage vectorsToColors(const LinearImage& image); +UTILS_PUBLIC LinearImage colorsToVectors(const LinearImage& image); + +// Creates a single-channel image by extracting the selected channel. +UTILS_PUBLIC LinearImage extractChannel(const LinearImage& image, uint32_t channel); + +// Constructs a multi-channel image by copying data from a sequence of single-channel images. +UTILS_PUBLIC LinearImage combineChannels(std::initializer_list images); +UTILS_PUBLIC LinearImage combineChannels(LinearImage const* img, size_t count); + +// Generates a new image with rows & columns swapped. +UTILS_PUBLIC LinearImage transpose(const LinearImage& image); + +// Extracts pixels by specifying a crop window where (0,0) is the top-left corner of the image. +// The boundary is specified as Left Top Right Bottom. +UTILS_PUBLIC +LinearImage cropRegion(const LinearImage& image, uint32_t l, uint32_t t, uint32_t r, uint32_t b); + +// Lexicographically compares two images, similar to memcmp. +UTILS_PUBLIC int compare(const LinearImage& a, const LinearImage& b, float epsilon = 0.0f); + +// Sets all pixels in all channels to the given value. +UTILS_PUBLIC void clearToValue(LinearImage& img, float value); + +// Called by the coordinate field generator to query if a pixel is within the region of interest. +using PresenceCallback = bool(*)(const LinearImage& img, uint32_t col, uint32_t row, void* user); + +// Generates a two-channel field of non-normalized coordinates that indicate the nearest pixel +// whose presence function returns true. This is the first step before generating a distance +// field or generalized Voronoi map. +UTILS_PUBLIC +LinearImage computeCoordField(const LinearImage& src, PresenceCallback presence, void* user); + +// Generates a single-channel Euclidean distance field with positive values outside the region +// of interest in the source image, and zero values inside. If sqrt is false, the computed +// distances are squared. If signed distance (SDF) is desired, this function can be called a second +// time using an inverted source field. +UTILS_PUBLIC LinearImage edtFromCoordField(const LinearImage& coordField, bool sqrt); + +// Dereferences the given coordinate field. Useful for creating Voronoi diagrams or dilated images. +UTILS_PUBLIC +LinearImage voronoiFromCoordField(const LinearImage& coordField, const LinearImage& src); + +// Copies content of a source image into a target image. Requires width/height/channels to match. +UTILS_PUBLIC void blitImage(LinearImage& target, const LinearImage& source); + +} // namespace image + + +#endif /* IMAGE_LINEARIMAGE_H */ diff --git a/package/ios/libs/filament/include/image/ImageSampler.h b/package/ios/libs/filament/include/image/ImageSampler.h new file mode 100644 index 00000000..e01da45e --- /dev/null +++ b/package/ios/libs/filament/include/image/ImageSampler.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_IMAGESAMPLER_H +#define IMAGE_IMAGESAMPLER_H + +#include + +#include + +namespace image { + +/** + * Value of a single point sample, allocated according to the number of image channels. + */ +struct UTILS_PUBLIC SingleSample { + float& operator[](int index) { return *(data + index); } + float* data = nullptr; + ~SingleSample(); +}; + +/** + * Controls the weighted average used across a window of source samples. + */ +enum class Filter { + DEFAULT, // Selects MITCHELL or LANCZOS dynamically. + BOX, // Computes the un-weighted average over the filter radius. + NEAREST, // Copies the source sample nearest to the center of the filter. + HERMITE, // Also known as "smoothstep", has some nice properties. + GAUSSIAN_SCALARS, // Standard Gaussian filter with sigma = 0.5 + GAUSSIAN_NORMALS, // Same as GAUSSIAN_SCALARS, but interpolates unitized vectors. + MITCHELL, // Cubic resampling per Mitchell-Netravali, default for magnification. + LANCZOS, // Popular sinc-based filter, default for minification. + MINIMUM // Takes a min val rather than avg, perhaps useful for depth maps and SDF's. +}; + +/** + * Defines a viewport inside the texture such that (0,0) is at the top-left corner of the top-left + * pixel, and (1,1) is at the bottom-right corner of the bottom-corner pixel. + */ +struct Region { + float left; + float top; + float right; + float bottom; +}; + +/** + * Transforms the texel fetching operation when sampling from adjacent images. + */ +enum class Orientation { + STANDARD = 0, + FLIP_X = 1 << 0, + FLIP_Y = 1 << 1, + FLIP_XY = FLIP_X | FLIP_Y +}; + +/** + * Specifies how to generate samples that lie outside the boundaries of the source region. + */ +struct Boundary { + enum { + EXCLUDE, // Ignore the samples and renormalize the filter. This is probably what you want. + REGION, // Keep samples that are outside sourceRegion if they are still within the image. + CLAMP, // Pretend the edge pixel is repeated forever. Gives edge pixels more weight. + REPEAT, // Resample from the region, wrapping back to the front of the row or column. + MIRROR, // Resample from the region but assume that it has been flipped. + COLOR, // Use the specified constant color. + NEIGHBOR // Sample from an adjacent image. + } mode = EXCLUDE; + SingleSample color; // Used only if mode = COLOR + LinearImage* neighbor = nullptr; // Used only if mode = NEIGHBOR + Orientation orientation; // Used only if mode = NEIGHBOR +}; + +/** + * Configuration for the resampleImage function. Provides reasonable defaults. + */ +struct ImageSampler { + Filter horizontalFilter = Filter::DEFAULT; + Filter verticalFilter = Filter::DEFAULT; + Region sourceRegion = {0, 0, 1, 1}; + float filterRadiusMultiplier = 1; + Boundary east; + Boundary north; + Boundary west; + Boundary south; +}; + +/** + * Resizes or blurs the given linear image, producing a new linear image with the given dimensions. + */ +UTILS_PUBLIC +LinearImage resampleImage(const LinearImage& source, uint32_t width, uint32_t height, + const ImageSampler& sampler); + +/** + * Resizes the given linear image using a simplified API that takes target dimensions and filter. + */ +UTILS_PUBLIC +LinearImage resampleImage(const LinearImage& source, uint32_t width, uint32_t height, + Filter filter = Filter::DEFAULT); + +/** + * Computes a single sample for the given texture coordinate and writes the resulting color + * components into the given output holder. + * + * For decent performance, do not call this across the entire image, instead call resampleImage. + * On the first call, pass in a default SingleSample to allocate the result holder. For example: + * + * SingleSample result; + * computeSingleSample(img, 0.5f, 0.5f, &result); + * printf("r g b = %f %f %f\n", result[0], result[1], result[2]); + * computeSingleSample(img, 0.9f, 0.1f, &result); + * printf("r g b = %f %f %f\n", result[0], result[1], result[2]); + * + * The x y coordinates live in "texture space" such that (0.0f, 0.0f) is the upper-left boundary of + * the top-left pixel and (+1.0f, +1.0f) is the lower-right boundary of the bottom-right pixel. + */ +UTILS_PUBLIC +void computeSingleSample(const LinearImage& source, float x, float y, SingleSample* result, + Filter filter = Filter::BOX); + +/** + * Generates a sequence of miplevels using the requested filter. To determine the number of mips + * it would take to get down to 1x1, see getMipmapCount. + * + * Source image need not be power-of-two. In the result vector, the half-size image is returned at + * index 0, the quarter-size image is at index 1, etc. Please note that the original-sized image is + * not included. + */ +UTILS_PUBLIC +void generateMipmaps(const LinearImage& source, Filter, LinearImage* result, uint32_t mipCount); + +/** + * Returns the number of miplevels it would take to downsample the given image down to 1x1. This + * number does not include the original image (i.e. mip 0). + */ +UTILS_PUBLIC +uint32_t getMipmapCount(const LinearImage& source); + +/** + * Given the string name of a filter, converts it to uppercase and returns the corresponding + * enum value. If no corresponding enumerant exists, returns DEFAULT. + */ +UTILS_PUBLIC +Filter filterFromString(const char* name); + +} // namespace image + +#endif /* IMAGE_IMAGESAMPLER_H */ diff --git a/package/ios/libs/filament/include/image/Ktx1Bundle.h b/package/ios/libs/filament/include/image/Ktx1Bundle.h new file mode 100644 index 00000000..430f92be --- /dev/null +++ b/package/ios/libs/filament/include/image/Ktx1Bundle.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_KTX1BUNDLE_H +#define IMAGE_KTX1BUNDLE_H + +#include + +#include + +#include +#include + +namespace image { + +struct KtxInfo { + uint32_t endianness; + uint32_t glType; + uint32_t glTypeSize; + uint32_t glFormat; + uint32_t glInternalFormat; + uint32_t glBaseInternalFormat; + uint32_t pixelWidth; + uint32_t pixelHeight; + uint32_t pixelDepth; +}; + +struct KtxBlobIndex { + uint32_t mipLevel; + uint32_t arrayIndex; + uint32_t cubeFace; +}; + +struct KtxBlobList; +struct KtxMetadata; + +/** + * Ktx1Bundle is a structured set of opaque data blobs that can be passed straight to the GPU, such + * that a single bundle corresponds to a single texture object. It is well suited for storing + * block-compressed texture data. + * + * One bundle may be comprised of several mipmap levels, cubemap faces, and array elements. The + * number of blobs is immutable, and is determined as follows. + * + * blob_count = mip_count * array_length * (cubemap ? 6 : 1) + * + * Bundles can be quickly serialized to a certain file format (see below link), but this class lives + * in the image lib rather than imageio because it has no dependencies, and does not support CPU + * decoding. + * + * https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ + */ +class UTILS_PUBLIC Ktx1Bundle { +public: + + ~Ktx1Bundle(); + + /** + * Creates a hierarchy of empty texture blobs, to be filled later via setBlob(). + */ + Ktx1Bundle(uint32_t numMipLevels, uint32_t arrayLength, bool isCubemap); + + /** + * Creates a new bundle by deserializing the given data. + * + * Typically, this constructor is used to consume the contents of a KTX file. + */ + Ktx1Bundle(uint8_t const* bytes, uint32_t nbytes); + + /** + * Serializes the bundle into the given target memory. Returns false if there's not enough + * memory. + * + * Typically, this method is used to write out the contents of a KTX file. + */ + bool serialize(uint8_t* destination, uint32_t numBytes) const; + + /** + * Computes the size (in bytes) of the serialized bundle. + */ + uint32_t getSerializedLength() const; + + /** + * Gets or sets information about the texture object, such as format and type. + */ + KtxInfo const& getInfo() const { return mInfo; } + KtxInfo& info() { return mInfo; } + + /** + * Gets or sets key/value metadata. + */ + const char* getMetadata(const char* key, size_t* valueSize = nullptr) const; + void setMetadata(const char* key, const char* value); + + /** + * Parses the key="sh" metadata and returns 3 bands of data. + * + * Assumes 3 bands for a total of 9 RGB coefficients. + * Returns true if successful. + */ + bool getSphericalHarmonics(filament::math::float3* result); + + /** + * Gets the number of miplevels (this is never zero). + */ + uint32_t getNumMipLevels() const { return mNumMipLevels; } + + /** + * Gets the number of array elements (this is never zero). + */ + uint32_t getArrayLength() const { return mArrayLength; } + + /** + * Returns whether or not this is a cubemap. + */ + bool isCubemap() const { return mNumCubeFaces > 1; } + + /** + * Retrieves a weak reference to a given data blob. Returns false if the given blob index is out + * of bounds, or if the blob at the given index is empty. + */ + bool getBlob(KtxBlobIndex index, uint8_t** data, uint32_t* size) const; + + /** + * Copies the given data into the blob at the given index, replacing whatever is already there. + * Returns false if the given blob index is out of bounds. + */ + bool setBlob(KtxBlobIndex index, uint8_t const* data, uint32_t size); + + /** + * Allocates the blob at the given index to the given number of bytes. This allows subsequent + * calls to setBlob to be thread-safe. + */ + bool allocateBlob(KtxBlobIndex index, uint32_t size); + + // The following constants help clients populate the "info" struct. Most of them have corollary + // constants in the OpenGL headers. + + static constexpr uint32_t R8 = 0x8229; + static constexpr uint32_t R8_SNORM = 0x8F94; + static constexpr uint32_t R8UI = 0x8232; + static constexpr uint32_t R8I = 0x8231; + static constexpr uint32_t STENCIL_INDEX8 = 0x8D48; + static constexpr uint32_t R16F = 0x822D; + static constexpr uint32_t R16UI = 0x8234; + static constexpr uint32_t R16I = 0x8233; + static constexpr uint32_t RG8 = 0x822B; + static constexpr uint32_t RG8_SNORM = 0x8F95; + static constexpr uint32_t RG8UI = 0x8238; + static constexpr uint32_t RG8I = 0x8237; + static constexpr uint32_t RGB565 = 0x8D62; + static constexpr uint32_t RGB5_A1 = 0x8057; + static constexpr uint32_t RGBA4 = 0x8056; + static constexpr uint32_t DEPTH_COMPONENT16 = 0x81A5; + static constexpr uint32_t RGB8 = 0x8051; + static constexpr uint32_t SRGB8 = 0x8C41; + static constexpr uint32_t RGB8_SNORM = 0x8F96; + static constexpr uint32_t RGB8UI = 0x8D7D; + static constexpr uint32_t RGB8I = 0x8D8F; + static constexpr uint32_t DEPTH_COMPONENT24 = 0x81A6; + static constexpr uint32_t R32F = 0x822E; + static constexpr uint32_t R32UI = 0x8236; + static constexpr uint32_t R32I = 0x8235; + static constexpr uint32_t RG16F = 0x822F; + static constexpr uint32_t RG16UI = 0x823A; + static constexpr uint32_t RG16I = 0x8239; + static constexpr uint32_t R11F_G11F_B10F = 0x8C3A; + static constexpr uint32_t RGB9_E5 = 0x8C3D; + static constexpr uint32_t RGBA8 = 0x8058; + static constexpr uint32_t SRGB8_ALPHA8 = 0x8C43; + static constexpr uint32_t RGBA8_SNORM = 0x8F97; + static constexpr uint32_t RGB10_A2 = 0x8059; + static constexpr uint32_t RGBA8UI = 0x8D7C; + static constexpr uint32_t RGBA8I = 0x8D8E; + static constexpr uint32_t DEPTH_COMPONENT32F = 0x8CAC; + static constexpr uint32_t DEPTH24_STENCIL8 = 0x88F0; + static constexpr uint32_t DEPTH32F_STENCIL8 = 0x8CAD; + static constexpr uint32_t RGB16F = 0x881B; + static constexpr uint32_t RGB16UI = 0x8D77; + static constexpr uint32_t RGB16I = 0x8D89; + static constexpr uint32_t RG32F = 0x8230; + static constexpr uint32_t RG32UI = 0x823C; + static constexpr uint32_t RG32I = 0x823B; + static constexpr uint32_t RGBA16F = 0x881A; + static constexpr uint32_t RGBA16UI = 0x8D76; + static constexpr uint32_t RGBA16I = 0x8D88; + static constexpr uint32_t RGB32F = 0x8815; + static constexpr uint32_t RGB32UI = 0x8D71; + static constexpr uint32_t RGB32I = 0x8D83; + static constexpr uint32_t RGBA32F = 0x8814; + static constexpr uint32_t RGBA32UI = 0x8D70; + static constexpr uint32_t RGBA32I = 0x8D82; + + static constexpr uint32_t RED = 0x1903; + static constexpr uint32_t RG = 0x8227; + static constexpr uint32_t RGB = 0x1907; + static constexpr uint32_t RGBA = 0x1908; + static constexpr uint32_t BGR = 0x80E0; + static constexpr uint32_t BGRA = 0x80E1; + static constexpr uint32_t LUMINANCE = 0x1909; + static constexpr uint32_t LUMINANCE_ALPHA = 0x190A; + + static constexpr uint32_t UNSIGNED_BYTE = 0x1401; + static constexpr uint32_t UNSIGNED_SHORT = 0x1403; + static constexpr uint32_t HALF_FLOAT = 0x140B; + static constexpr uint32_t FLOAT = 0x1406; + + static constexpr uint32_t ENDIAN_DEFAULT = 0x04030201; + + static constexpr uint32_t RGB_S3TC_DXT1 = 0x83F0; + static constexpr uint32_t RGBA_S3TC_DXT1 = 0x83F1; + static constexpr uint32_t RGBA_S3TC_DXT3 = 0x83F2; + static constexpr uint32_t RGBA_S3TC_DXT5 = 0x83F3; + + static constexpr uint32_t R_RGTC_BC4_UNORM = 0x8DBB; + static constexpr uint32_t R_RGTC_BC4_SNORM = 0x8DBC; + static constexpr uint32_t RG_RGTC_BC5_UNORM = 0x8DBD; + static constexpr uint32_t RG_RGTC_BC5_SNORM = 0x8DBE; + + static constexpr uint32_t RGBA_BPTC_BC7 = 0x8E8C; + static constexpr uint32_t SRGB8_ALPHA8_BPTC_BC7 = 0x8E8D; + static constexpr uint32_t RGB_BPTC_BC6H_SNORM = 0x8E8E; + static constexpr uint32_t RGB_BPTC_BC6H_UNORM = 0x8E8F; + + static constexpr uint32_t RGBA_ASTC_4x4 = 0x93B0; + static constexpr uint32_t RGBA_ASTC_5x4 = 0x93B1; + static constexpr uint32_t RGBA_ASTC_5x5 = 0x93B2; + static constexpr uint32_t RGBA_ASTC_6x5 = 0x93B3; + static constexpr uint32_t RGBA_ASTC_6x6 = 0x93B4; + static constexpr uint32_t RGBA_ASTC_8x5 = 0x93B5; + static constexpr uint32_t RGBA_ASTC_8x6 = 0x93B6; + static constexpr uint32_t RGBA_ASTC_8x8 = 0x93B7; + static constexpr uint32_t RGBA_ASTC_10x5 = 0x93B8; + static constexpr uint32_t RGBA_ASTC_10x6 = 0x93B9; + static constexpr uint32_t RGBA_ASTC_10x8 = 0x93BA; + static constexpr uint32_t RGBA_ASTC_10x10 = 0x93BB; + static constexpr uint32_t RGBA_ASTC_12x10 = 0x93BC; + static constexpr uint32_t RGBA_ASTC_12x12 = 0x93BD; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_4x4 = 0x93D0; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_5x4 = 0x93D1; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_5x5 = 0x93D2; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_6x5 = 0x93D3; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_6x6 = 0x93D4; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x5 = 0x93D5; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x6 = 0x93D6; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_8x8 = 0x93D7; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x5 = 0x93D8; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x6 = 0x93D9; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x8 = 0x93DA; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_10x10 = 0x93DB; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_12x10 = 0x93DC; + static constexpr uint32_t SRGB8_ALPHA8_ASTC_12x12 = 0x93DD; + + static constexpr uint32_t R11_EAC = 0x9270; + static constexpr uint32_t SIGNED_R11_EAC = 0x9271; + static constexpr uint32_t RG11_EAC = 0x9272; + static constexpr uint32_t SIGNED_RG11_EAC = 0x9273; + static constexpr uint32_t RGB8_ETC2 = 0x9274; + static constexpr uint32_t SRGB8_ETC2 = 0x9275; + static constexpr uint32_t RGB8_ALPHA1_ETC2 = 0x9276; + static constexpr uint32_t SRGB8_ALPHA1_ETC = 0x9277; + static constexpr uint32_t RGBA8_ETC2_EAC = 0x9278; + static constexpr uint32_t SRGB8_ALPHA8_ETC2_EAC = 0x9279; + +private: + image::KtxInfo mInfo = {}; + uint32_t mNumMipLevels; + uint32_t mArrayLength; + uint32_t mNumCubeFaces; + std::unique_ptr mBlobs; + std::unique_ptr mMetadata; +}; + +} // namespace image + +#endif /* IMAGE_Ktx1Bundle_H */ diff --git a/package/ios/libs/filament/include/image/LinearImage.h b/package/ios/libs/filament/include/image/LinearImage.h new file mode 100644 index 00000000..de46a787 --- /dev/null +++ b/package/ios/libs/filament/include/image/LinearImage.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef IMAGE_LINEARIMAGE_H +#define IMAGE_LINEARIMAGE_H + +#include + +#include + +/** + * Types and free functions for the Filament core imaging library, primarily used for offline tools, + * but with minimal dependencies to support potential use by the renderer. + */ +namespace image { + +/** + * LinearImage is a handle to packed floating point data arranged into a row-major grid. + * + * We use this object as input/output for core algorithms that wish to be agnostic of source and + * destination formats. The number of channels is arbitrary (1 or more) but we often use 3-channel + * images to represent color data. + * + * The underlying pixel data has shared ownership semantics to allow clients to easily pass around + * the image object without incurring a deep copy. Shared access to pixels is not thread safe. + * + * By convention, we do not use channel major order (i.e. planar). However we provide a free + * function in ImageOps to combine planar data. Pixels are stored such that the row stride is simply + * width * channels * sizeof(float). + */ +class UTILS_PUBLIC LinearImage { +public: + + ~LinearImage(); + + /** + * Allocates a zeroed-out image. + */ + LinearImage(uint32_t width, uint32_t height, uint32_t channels); + + /** + * Makes a shallow copy with shared pixel data. + */ + LinearImage(const LinearImage& that); + LinearImage& operator=(const LinearImage& that); + + /** + * Creates an empty (invalid) image. + */ + LinearImage() : mDataRef(nullptr), mData(nullptr), mWidth(0), mHeight(0), mChannels(0) {} + operator bool() const { return mData != nullptr; } + + /** + * Gets a pointer to the underlying pixel data. + */ + float* getPixelRef() { return mData; } + template T* get() { return reinterpret_cast(mData); } + + /** + * Gets a pointer to immutable pixel data. + */ + float const* getPixelRef() const { return mData; } + template T const* get() const { return reinterpret_cast(mData); } + + /** + * Gets a pointer to the pixel data at the given column and row. (not bounds checked) + */ + float* getPixelRef(uint32_t column, uint32_t row) { + return mData + (column + row * mWidth) * mChannels; + } + + template + T* get(uint32_t column, uint32_t row) { + return reinterpret_cast(getPixelRef(column, row)); + } + + /** + * Gets a pointer to the immutable pixel data at the given column and row. (not bounds checked) + */ + float const* getPixelRef(uint32_t column, uint32_t row) const { + return mData + (column + row * mWidth) * mChannels; + } + + template + T const* get(uint32_t column, uint32_t row) const { + return reinterpret_cast(getPixelRef(column, row)); + } + + uint32_t getWidth() const { return mWidth; } + uint32_t getHeight() const { return mHeight; } + uint32_t getChannels() const { return mChannels; } + void reset() { *this = LinearImage(); } + bool isValid() const { return mData; } + +private: + + struct SharedReference; + SharedReference* mDataRef = nullptr; + + float* mData; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mChannels; +}; + +} // namespace image + +#endif /* IMAGE_LINEARIMAGE_H */ diff --git a/package/ios/libs/filament/include/ktxreader/Ktx1Reader.h b/package/ios/libs/filament/include/ktxreader/Ktx1Reader.h new file mode 100644 index 00000000..ca980c1c --- /dev/null +++ b/package/ios/libs/filament/include/ktxreader/Ktx1Reader.h @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#ifndef KTXREADER_KTX1READER_H +#define KTXREADER_KTX1READER_H + +#include + +#include + +namespace filament { + class Engine; +} + +namespace ktxreader { + +using KtxInfo = image::KtxInfo; +using Ktx1Bundle = image::Ktx1Bundle; + +/** + * Allows clients to create Filament textures from Ktx1Bundle objects. + */ +namespace Ktx1Reader { + + using Texture = filament::Texture; + using Engine = filament::Engine; + + using TextureFormat = Texture::InternalFormat; + using CompressedPixelDataType = Texture::CompressedType; + using PixelDataType = Texture::Type; + using PixelDataFormat = Texture::Format; + using PixelBufferDescriptor = Texture::PixelBufferDescriptor; + + using Callback = void(*)(void* userdata); + + CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info); + PixelDataType toPixelDataType(const KtxInfo& info); + PixelDataFormat toPixelDataFormat(const KtxInfo& info); + bool isCompressed(const KtxInfo& info); + TextureFormat toTextureFormat(const KtxInfo& info); + + template + T toCompressedFilamentEnum(uint32_t format) { + switch (format) { + case Ktx1Bundle::RGB_S3TC_DXT1: return T::DXT1_RGB; + case Ktx1Bundle::RGBA_S3TC_DXT1: return T::DXT1_RGBA; + case Ktx1Bundle::RGBA_S3TC_DXT3: return T::DXT3_RGBA; + case Ktx1Bundle::RGBA_S3TC_DXT5: return T::DXT5_RGBA; + case Ktx1Bundle::R_RGTC_BC4_UNORM: return T::RED_RGTC1; + case Ktx1Bundle::R_RGTC_BC4_SNORM: return T::SIGNED_RED_RGTC1; + case Ktx1Bundle::RG_RGTC_BC5_UNORM: return T::RED_GREEN_RGTC2; + case Ktx1Bundle::RG_RGTC_BC5_SNORM: return T::SIGNED_RED_GREEN_RGTC2; + case Ktx1Bundle::RGBA_BPTC_BC7: return T::RGBA_BPTC_UNORM; + case Ktx1Bundle::SRGB8_ALPHA8_BPTC_BC7: return T::SRGB_ALPHA_BPTC_UNORM; + case Ktx1Bundle::RGB_BPTC_BC6H_SNORM: return T::RGB_BPTC_SIGNED_FLOAT; + case Ktx1Bundle::RGB_BPTC_BC6H_UNORM: return T::RGB_BPTC_UNSIGNED_FLOAT; + case Ktx1Bundle::RGBA_ASTC_4x4: return T::RGBA_ASTC_4x4; + case Ktx1Bundle::RGBA_ASTC_5x4: return T::RGBA_ASTC_5x4; + case Ktx1Bundle::RGBA_ASTC_5x5: return T::RGBA_ASTC_5x5; + case Ktx1Bundle::RGBA_ASTC_6x5: return T::RGBA_ASTC_6x5; + case Ktx1Bundle::RGBA_ASTC_6x6: return T::RGBA_ASTC_6x6; + case Ktx1Bundle::RGBA_ASTC_8x5: return T::RGBA_ASTC_8x5; + case Ktx1Bundle::RGBA_ASTC_8x6: return T::RGBA_ASTC_8x6; + case Ktx1Bundle::RGBA_ASTC_8x8: return T::RGBA_ASTC_8x8; + case Ktx1Bundle::RGBA_ASTC_10x5: return T::RGBA_ASTC_10x5; + case Ktx1Bundle::RGBA_ASTC_10x6: return T::RGBA_ASTC_10x6; + case Ktx1Bundle::RGBA_ASTC_10x8: return T::RGBA_ASTC_10x8; + case Ktx1Bundle::RGBA_ASTC_10x10: return T::RGBA_ASTC_10x10; + case Ktx1Bundle::RGBA_ASTC_12x10: return T::RGBA_ASTC_12x10; + case Ktx1Bundle::RGBA_ASTC_12x12: return T::RGBA_ASTC_12x12; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_4x4: return T::SRGB8_ALPHA8_ASTC_4x4; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x4: return T::SRGB8_ALPHA8_ASTC_5x4; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x5: return T::SRGB8_ALPHA8_ASTC_5x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x5: return T::SRGB8_ALPHA8_ASTC_6x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x6: return T::SRGB8_ALPHA8_ASTC_6x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x5: return T::SRGB8_ALPHA8_ASTC_8x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x6: return T::SRGB8_ALPHA8_ASTC_8x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x8: return T::SRGB8_ALPHA8_ASTC_8x8; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x5: return T::SRGB8_ALPHA8_ASTC_10x5; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x6: return T::SRGB8_ALPHA8_ASTC_10x6; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x8: return T::SRGB8_ALPHA8_ASTC_10x8; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x10: return T::SRGB8_ALPHA8_ASTC_10x10; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x10: return T::SRGB8_ALPHA8_ASTC_12x10; + case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x12: return T::SRGB8_ALPHA8_ASTC_12x12; + case Ktx1Bundle::R11_EAC: return T::EAC_R11; + case Ktx1Bundle::SIGNED_R11_EAC: return T::EAC_R11_SIGNED; + case Ktx1Bundle::RG11_EAC: return T::EAC_RG11; + case Ktx1Bundle::SIGNED_RG11_EAC: return T::EAC_RG11_SIGNED; + case Ktx1Bundle::RGB8_ETC2: return T::ETC2_RGB8; + case Ktx1Bundle::SRGB8_ETC2: return T::ETC2_SRGB8; + case Ktx1Bundle::RGB8_ALPHA1_ETC2: return T::ETC2_RGB8_A1; + case Ktx1Bundle::SRGB8_ALPHA1_ETC: return T::ETC2_SRGB8_A1; + case Ktx1Bundle::RGBA8_ETC2_EAC: return T::ETC2_EAC_RGBA8; + case Ktx1Bundle::SRGB8_ALPHA8_ETC2_EAC: return T::ETC2_EAC_SRGBA8; + } + return (T) 0xffff; + } + + /** + * Creates a Texture object from a KTX file and populates all of its faces and miplevels. + * + * @param engine Used to create the Filament Texture + * @param ktx In-memory representation of a KTX file + * @param srgb Requests an sRGB format from the KTX file + * @param callback Gets called after all texture data has been uploaded to the GPU + * @param userdata Passed into the callback + */ + Texture* createTexture(Engine* engine, const Ktx1Bundle& ktx, bool srgb, + Callback callback, void* userdata); + + /** + * Creates a Texture object from a KTX bundle, populates all of its faces and miplevels, + * and automatically destroys the bundle after all the texture data has been uploaded. + * + * @param engine Used to create the Filament Texture + * @param ktx In-memory representation of a KTX file + * @param srgb Requests an sRGB format from the KTX file + */ + Texture* createTexture(Engine* engine, Ktx1Bundle* ktx, bool srgb); + + CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info); + + PixelDataType toPixelDataType(const KtxInfo& info); + + PixelDataFormat toPixelDataFormat(const KtxInfo& info); + + bool isCompressed(const KtxInfo& info); + + bool isSrgbTextureFormat(TextureFormat format); + + TextureFormat toTextureFormat(const KtxInfo& info); + +} // namespace Ktx1Reader +} // namespace ktxreader + +#endif diff --git a/package/ios/libs/filament/include/ktxreader/Ktx2Reader.h b/package/ios/libs/filament/include/ktxreader/Ktx2Reader.h new file mode 100644 index 00000000..0994a5e2 --- /dev/null +++ b/package/ios/libs/filament/include/ktxreader/Ktx2Reader.h @@ -0,0 +1,203 @@ +/* + * 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. + */ + +#ifndef KTXREADER_KTX2READER_H +#define KTXREADER_KTX2READER_H + +#include +#include + +#include + +#include + +namespace filament { + class Engine; +} + +namespace basist { + class ktx2_transcoder; +} + +namespace ktxreader { + +class Ktx2Reader { + public: + using Engine = filament::Engine; + using Texture = filament::Texture; + enum class TransferFunction { LINEAR, sRGB }; + + enum class Result { + SUCCESS, + COMPRESSED_TRANSCODE_FAILURE, + UNCOMPRESSED_TRANSCODE_FAILURE, + FORMAT_UNSUPPORTED, + FORMAT_ALREADY_REQUESTED, + }; + + Ktx2Reader(Engine& engine, bool quiet = false); + ~Ktx2Reader(); + + /** + * Requests that the reader constructs Filament textures with given internal format. + * + * This MUST be called at least once before calling load(). + * + * As a reminder, a basis-encoded KTX2 can be quickly transcoded to any number of formats, + * so you need to tell it what formats your hw supports. That's why this method exists. + * + * Call requestFormat as many times as needed; formats that are submitted early are + * considered higher priority. + * + * If BasisU knows a priori that the given format is not available (e.g. if the build has + * disabled it), the format is not added and FORMAT_UNSUPPORTED is returned. + * + * Returns FORMAT_ALREADY_REQUESTED if the given format has already been requested. + * + * Hint: BasisU supports the following uncompressed formats: RGBA8, RGB565, RGBA4. + */ + Result requestFormat(Texture::InternalFormat format) noexcept; + + /** + * Removes the given format from the list, or does nothing if it hasn't been requested. + */ + void unrequestFormat(Texture::InternalFormat format) noexcept; + + /** + * Attempts to create and load a Filament texture from the given KTX2 blob. + * + * If none of the requested formats can be extracted from the data, this returns null. + * + * This method iterates through the requested format list, checking each one against the + * platform's capabilities and its availability from the transcoder. When a suitable format + * is determined, it then performs lossless decompression (zstd) before transcoding the data + * into the final format. + * + * The transfer function specified here is used in two ways: + * 1) It is checked against the transfer function that was specified as metadata + * in the KTX2 blob. If they do not match, this method fails. + * 2) It is used as a filter when determining the final internal format. + */ + Texture* load(const void* data, size_t size, TransferFunction transfer); + + /** + * Asynchronous Interface + * ====================== + * + * Alternative API suitable for asynchronous transcoding of mipmap levels. + * If unsure that you need to use this, then don't, just call load() instead. + * Usage pseudocode: + * + * auto async = reader->asyncCreate(data, size, TransferFunction::LINEAR); + * mTexture = async->getTexture(); + * auto backgroundThread = spawnThread({ async->doTranscoding(); }) + * backgroundThread.wait(); + * async->uploadImages(); + * reader->asyncDestroy(async); + * + * In the documentation comments, "foreground thread" refers to the thread that the + * Filament Engine was created on. + */ + class Async { + public: + /** + * Retrieves the Texture object. + * + * The texture is available immediately, but does not have its miplevels ready until + * after doTranscoding() and the subsequent uploadImages() have been completed. The + * caller has ownership over this texture and is responsible for freeing it after all + * miplevels have been uploaded. + */ + Texture* getTexture() const noexcept; + + /** + * Loads all mipmaps from the KTX2 file and transcodes them to the resolved format. + * + * This does not return until all mipmaps have been transcoded. This is typically + * called from a background thread. + */ + Result doTranscoding(); + + /** + * Uploads pending mipmaps to the texture. + * + * This can safely be called while doTranscoding() is still working in another thread. + * Since this calls Texture::setImage(), it should be called from the foreground thread; + * see "Thread safety" in the documentation for filament::Engine. + */ + void uploadImages(); + + protected: + Async() noexcept = default; + virtual ~Async(); + + public: + Async(Async const&) = delete; + Async(Async&&) = delete; + Async& operator=(Async const&) = delete; + Async& operator=(Async&&) = delete; + + friend class Ktx2Reader; + }; + + /** + * Creates a texture without starting the transcode process. + * + * This method is an alternative to load() that allows users to populate mipmap levels + * asynchronously. The texture object however is still created synchronously. + * + * - For a usage example, see the documentation for the Async object. + * - Creates a copy of the given buffer, allowing clients to free it immediately. + * - Returns null if none of the requested formats can be extracted from the data. + * + * This method iterates through the requested format list, checking each one against the + * platform's capabilities and its availability from the transcoder. When a suitable format + * is determined, it then performs lossless decompression (zstd) before transcoding the data + * into the final format. + * + * The transfer function specified here is used in two ways: + * 1) It is checked against the transfer function that was specified as metadata + * in the KTX2 blob. If they do not match, this method fails. + * 2) It is used as a filter when determining the final internal format. + */ + Async* asyncCreate(const void* data, size_t size, TransferFunction transfer); + + /** + * Frees the given async object and sets it to null. + * + * This frees the original source data (i.e. the raw content of the KTX2 file) but does not + * free the associated Texture object. This can be done after transcoding has finished. + */ + void asyncDestroy(Async** async); + + private: + Ktx2Reader(const Ktx2Reader&) = delete; + Ktx2Reader& operator=(const Ktx2Reader&) = delete; + Ktx2Reader(Ktx2Reader&& that) noexcept = delete; + Ktx2Reader& operator=(Ktx2Reader&& that) noexcept = delete; + + Texture* createTexture(basist::ktx2_transcoder* transcoder, const void* data, + size_t size, TransferFunction transfer); + + Engine& mEngine; + basist::ktx2_transcoder* const mTranscoder; + utils::FixedCapacityVector mRequestedFormats; + bool mQuiet; +}; + +} // namespace ktxreader + +#endif diff --git a/package/ios/libs/filament/include/math/TMatHelpers.h b/package/ios/libs/filament/include/math/TMatHelpers.h new file mode 100644 index 00000000..ec66650c --- /dev/null +++ b/package/ios/libs/filament/include/math/TMatHelpers.h @@ -0,0 +1,807 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TMATHELPERS_H +#define TNT_MATH_TMATHELPERS_H + +#include +#include +#include + +#include // for std::swap and std::min +#include // for std:: namespace + +#include +#include +#include + +namespace filament { +namespace math { +namespace details { +// ------------------------------------------------------------------------------------- + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/mat*.h + */ + + +/* + * Matrix utilities + */ + +namespace matrix { + +/* + * Matrix inversion + */ +template +constexpr MATRIX MATH_PURE gaussJordanInverse(MATRIX src) { + typedef typename MATRIX::value_type T; + constexpr unsigned int N = MATRIX::NUM_ROWS; + MATRIX inverted; + + for (size_t i = 0; i < N; ++i) { + // look for largest element in i'th column + size_t swap = i; + T t = src[i][i] < 0 ? -src[i][i] : src[i][i]; + for (size_t j = i + 1; j < N; ++j) { + const T t2 = src[j][i] < 0 ? -src[j][i] : src[j][i]; + if (t2 > t) { + swap = j; + t = t2; + } + } + + if (swap != i) { + // swap columns. + std::swap(src[i], src[swap]); + std::swap(inverted[i], inverted[swap]); + } + + const T denom(src[i][i]); + for (size_t k = 0; k < N; ++k) { + src[i][k] /= denom; + inverted[i][k] /= denom; + } + + // Factor out the lower triangle + for (size_t j = 0; j < N; ++j) { + if (j != i) { + const T t = src[j][i]; + for (size_t k = 0; k < N; ++k) { + src[j][k] -= src[i][k] * t; + inverted[j][k] -= inverted[i][k] * t; + } + } + } + } + + return inverted; +} + +//------------------------------------------------------------------------------ +// 2x2 matrix inverse is easy. +template +constexpr MATRIX MATH_PURE fastInverse2(const MATRIX& x) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b | + // | c d | + // + // The analytic inverse is + // | d -b | + // | -c a | / (a d - b c) + // + // Importantly, our matrices are column-major! + + MATRIX inverted{}; + + const T a = x[0][0]; + const T c = x[0][1]; + const T b = x[1][0]; + const T d = x[1][1]; + + const T det((a * d) - (b * c)); + inverted[0][0] = d / det; + inverted[0][1] = -c / det; + inverted[1][0] = -b / det; + inverted[1][1] = a / det; + return inverted; +} + +//------------------------------------------------------------------------------ +// From the Wikipedia article on matrix inversion's section on fast 3x3 +// matrix inversion: +// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices +template +constexpr MATRIX MATH_PURE fastInverse3(const MATRIX& x) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b c | + // | d e f | + // | g h i | + // + // The analytic inverse is + // | A B C |^T + // | D E F | + // | G H I | / determinant + // + // Which is + // | A D G | + // | B E H | + // | C F I | / determinant + // + // Where: + // A = (ei - fh), B = (fg - di), C = (dh - eg) + // D = (ch - bi), E = (ai - cg), F = (bg - ah) + // G = (bf - ce), H = (cd - af), I = (ae - bd) + // + // and the determinant is a*A + b*B + c*C (The rule of Sarrus) + // + // Importantly, our matrices are column-major! + + MATRIX inverted{}; + + const T a = x[0][0]; + const T b = x[1][0]; + const T c = x[2][0]; + const T d = x[0][1]; + const T e = x[1][1]; + const T f = x[2][1]; + const T g = x[0][2]; + const T h = x[1][2]; + const T i = x[2][2]; + + // Do the full analytic inverse + const T A = e * i - f * h; + const T B = f * g - d * i; + const T C = d * h - e * g; + inverted[0][0] = A; // A + inverted[0][1] = B; // B + inverted[0][2] = C; // C + inverted[1][0] = c * h - b * i; // D + inverted[1][1] = a * i - c * g; // E + inverted[1][2] = b * g - a * h; // F + inverted[2][0] = b * f - c * e; // G + inverted[2][1] = c * d - a * f; // H + inverted[2][2] = a * e - b * d; // I + + const T det(a * A + b * B + c * C); + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + inverted[col][row] /= det; + } + } + + return inverted; +} + + +//------------------------------------------------------------------------------ +// Determinant and cofactor + +// this is just a dummy matrix helper +template +class Matrix { + T m[ORDER][ORDER]; +public: + constexpr auto operator[](size_t i) const noexcept { return m[i]; } + + constexpr auto& operator[](size_t i) noexcept { return m[i]; } + + static constexpr Matrix submatrix(Matrix in, size_t row, size_t col) noexcept { + size_t colCount = 0, rowCount = 0; + Matrix dest{}; + for (size_t i = 0; i < ORDER; i++) { + if (i != row) { + colCount = 0; + for (size_t j = 0; j < ORDER; j++) { + if (j != col) { + dest[rowCount][colCount] = in[i][j]; + colCount++; + } + } + rowCount++; + } + } + return dest; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + T det = {}; + for (size_t i = 0; i < O; i++) { + T m = Determinant::determinant(Matrix::submatrix(in, 0, i)); + T factor = (i % 2 == 1) ? T(-1) : T(1); + det += factor * in[0][i] * m; + } + return det; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + return + in[0][0] * in[1][1] * in[2][2] + + in[1][0] * in[2][1] * in[0][2] + + in[2][0] * in[0][1] * in[1][2] - + in[2][0] * in[1][1] * in[0][2] - + in[1][0] * in[0][1] * in[2][2] - + in[0][0] * in[2][1] * in[1][2]; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { + return in[0][0] * in[1][1] - in[0][1] * in[1][0]; + } +}; + +template +struct Determinant { + static constexpr T determinant(Matrix in) { return in[0][0]; } +}; + +template +constexpr MATRIX MATH_PURE cofactor(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + MATRIX out; + constexpr size_t order = MATRIX::NUM_COLS; + + Matrix in{}; + for (size_t i = 0; i < order; i++) { + for (size_t j = 0; j < order; j++) { + in[i][j] = m[i][j]; + } + } + + for (size_t i = 0; i < order; i++) { + for (size_t j = 0; j < order; j++) { + T factor = ((i + j) % 2 == 1) ? T(-1) : T(1); + out[i][j] = Determinant::determinant( + Matrix::submatrix(in, i, j)) * factor; + } + } + return out; +} + +template +constexpr MATRIX MATH_PURE fastCofactor2(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b | + // | c d | + // + // The cofactor are + // | d -c | + // | -b a | + // + // Importantly, our matrices are column-major! + + MATRIX cof{}; + + const T a = m[0][0]; + const T c = m[0][1]; + const T b = m[1][0]; + const T d = m[1][1]; + + cof[0][0] = d; + cof[0][1] = -b; + cof[1][0] = -c; + cof[1][1] = a; + return cof; +} + +template +constexpr MATRIX MATH_PURE fastCofactor3(const MATRIX& m) { + typedef typename MATRIX::value_type T; + + // Assuming the input matrix is: + // | a b c | + // | d e f | + // | g h i | + // + // The cofactor are + // | A B C | + // | D E F | + // | G H I | + + // Where: + // A = (ei - fh), B = (fg - di), C = (dh - eg) + // D = (ch - bi), E = (ai - cg), F = (bg - ah) + // G = (bf - ce), H = (cd - af), I = (ae - bd) + + // Importantly, our matrices are column-major! + + MATRIX cof{}; + + const T a = m[0][0]; + const T b = m[1][0]; + const T c = m[2][0]; + const T d = m[0][1]; + const T e = m[1][1]; + const T f = m[2][1]; + const T g = m[0][2]; + const T h = m[1][2]; + const T i = m[2][2]; + + cof[0][0] = e * i - f * h; // A + cof[0][1] = c * h - b * i; // D + cof[0][2] = b * f - c * e; // G + cof[1][0] = f * g - d * i; // B + cof[1][1] = a * i - c * g; // E + cof[1][2] = c * d - a * f; // H + cof[2][0] = d * h - e * g; // C + cof[2][1] = b * g - a * h; // F + cof[2][2] = a * e - b * d; // I + + return cof; +} + + +/** + * Cofactor function which switches on the matrix size. + */ +template> +inline constexpr MATRIX MATH_PURE cof(const MATRIX& matrix) { + return (MATRIX::NUM_ROWS == 2) ? fastCofactor2(matrix) : + ((MATRIX::NUM_ROWS == 3) ? fastCofactor3(matrix) : + cofactor(matrix)); +} + +/** + * Determinant of a matrix + */ +template> +inline constexpr typename MATRIX::value_type MATH_PURE det(const MATRIX& matrix) { + typedef typename MATRIX::value_type T; + constexpr unsigned int N = MATRIX::NUM_ROWS; + Matrix in{}; + for (size_t i = 0; i < N; i++) { + for (size_t j = 0; j < N; j++) { + in[i][j] = matrix[i][j]; + } + } + return Determinant::determinant(in); +} + +/** + * Inversion function which switches on the matrix size. + * @warning This function assumes the matrix is invertible. The result is + * undefined if it is not. It is the responsibility of the caller to + * make sure the matrix is not singular. + */ +template> +inline constexpr MATRIX MATH_PURE inverse(const MATRIX& matrix) { + return (MATRIX::NUM_ROWS == 2) ? fastInverse2(matrix) : + ((MATRIX::NUM_ROWS == 3) ? fastInverse3(matrix) : + gaussJordanInverse(matrix)); +} + +template> +constexpr MATRIX_R MATH_PURE multiply(MATRIX_A lhs, MATRIX_B rhs) { + // pre-requisite: + // lhs : D columns, R rows + // rhs : C columns, D rows + // res : C columns, R rows + MATRIX_R res{}; + for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) { + res[col] = lhs * rhs[col]; + } + return res; +} + +template> +inline constexpr MATRIX MATH_PURE transpose(MATRIX m) { + // for now we only handle square matrix transpose + MATRIX result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) { + result[col][row] = m[row][col]; + } + } + return result; +} + +template> +inline constexpr typename MATRIX::value_type MATH_PURE trace(MATRIX m) { + typename MATRIX::value_type result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + result += m[col][col]; + } + return result; +} + +template> +inline constexpr typename MATRIX::col_type MATH_PURE diag(MATRIX m) { + typename MATRIX::col_type result{}; + for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { + result[col] = m[col][col]; + } + return result; +} + +//------------------------------------------------------------------------------ +// This is taken from the Imath MatrixAlgo code, and is identical to Eigen. +template +TQuaternion extractQuat(const MATRIX& mat) { + typedef typename MATRIX::value_type T; + + TQuaternion quat(TQuaternion::NO_INIT); + + // Compute the trace to see if it is positive or not. + const T trace = mat[0][0] + mat[1][1] + mat[2][2]; + + // check the sign of the trace + if (MATH_LIKELY(trace > 0)) { + // trace is positive + T s = std::sqrt(trace + 1); + quat.w = T(0.5) * s; + s = T(0.5) / s; + quat.x = (mat[1][2] - mat[2][1]) * s; + quat.y = (mat[2][0] - mat[0][2]) * s; + quat.z = (mat[0][1] - mat[1][0]) * s; + } else { + // trace is negative + + // Find the index of the greatest diagonal + size_t i = 0; + if (mat[1][1] > mat[0][0]) { i = 1; } + if (mat[2][2] > mat[i][i]) { i = 2; } + + // Get the next indices: (n+1)%3 + static constexpr size_t next_ijk[3] = { 1, 2, 0 }; + size_t j = next_ijk[i]; + size_t k = next_ijk[j]; + T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1); + quat[i] = T(0.5) * s; + if (s != 0) { + s = T(0.5) / s; + } + quat.w = (mat[j][k] - mat[k][j]) * s; + quat[j] = (mat[i][j] + mat[j][i]) * s; + quat[k] = (mat[i][k] + mat[k][i]) * s; + } + return quat; +} + +} // namespace matrix + +// ------------------------------------------------------------------------------------- + +/* + * TMatProductOperators implements basic arithmetic and basic compound assignments + * operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TMatProductOperators BASE will automatically + * get all the functionality here. + */ + +template class BASE, typename T, + template class VEC> +class TMatProductOperators { +public: + // matrix *= matrix + template + constexpr BASE& operator*=(const BASE& rhs) { + BASE& lhs(static_cast< BASE& >(*this)); + lhs = matrix::multiply>(lhs, rhs); + return lhs; + } + + // matrix *= scalar + template> + constexpr BASE& operator*=(U v) { + BASE& lhs(static_cast< BASE& >(*this)); + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + lhs[col] *= v; + } + return lhs; + } + + // matrix /= scalar + template> + constexpr BASE& operator/=(U v) { + BASE& lhs(static_cast< BASE& >(*this)); + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + lhs[col] /= v; + } + return lhs; + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + // matrix * matrix + template + friend inline constexpr BASE> MATH_PURE + operator*(BASE lhs, BASE rhs) { + return matrix::multiply>>(lhs, rhs); + } + + // matrix * vector + template + friend inline constexpr typename BASE>::col_type MATH_PURE + operator*(const BASE& lhs, const VEC& rhs) { + typename BASE>::col_type result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result += lhs[col] * rhs[col]; + } + return result; + } + + // row-vector * matrix + template + friend inline constexpr typename BASE>::row_type MATH_PURE + operator*(const VEC& lhs, const BASE& rhs) { + typename BASE>::row_type result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = dot(lhs, rhs[col]); + } + return result; + } + + // matrix * scalar + template> + friend inline constexpr BASE> MATH_PURE + operator*(const BASE& lhs, U rhs) { + BASE> result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = lhs[col] * rhs; + } + return result; + } + + // scalar * matrix + template> + friend inline constexpr BASE> MATH_PURE + operator*(U rhs, const BASE& lhs) { + return lhs * rhs; + } + + // matrix / scalar + template> + friend inline constexpr BASE> MATH_PURE + operator/(const BASE& lhs, U rhs) { + BASE> result{}; + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + result[col] = lhs[col] / rhs; + } + return result; + } +}; + +/* + * TMatSquareFunctions implements functions on a matrix of type BASE. + * + * BASE only needs to implement: + * - operator[] + * - col_type + * - row_type + * - COL_SIZE + * - ROW_SIZE + * + * By simply inheriting from TMatSquareFunctions BASE will automatically + * get all the functionality here. + */ + +template class BASE, typename T> +class TMatSquareFunctions { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + friend inline constexpr BASE MATH_PURE inverse(const BASE& matrix) { + return matrix::inverse(matrix); + } + + friend inline constexpr BASE MATH_PURE cof(const BASE& matrix) { + return matrix::cof(matrix); + } + + friend inline constexpr BASE MATH_PURE transpose(BASE m) { + return matrix::transpose(m); + } + + friend inline constexpr T MATH_PURE trace(BASE m) { + return matrix::trace(m); + } + + friend inline constexpr T MATH_PURE det(const BASE& m) { + return matrix::det(m); + } + + // unclear why we have to use 'auto' here. 'typename BASE::col_type' produces + // error: no type named 'col_type' in 'filament::math::details::TMat44' + friend inline constexpr auto MATH_PURE diag(const BASE& m) { + return matrix::diag(m); + } +}; + +template class BASE, typename T> +class TMatHelpers { +public: + constexpr inline size_t getColumnSize() const { return BASE::COL_SIZE; } + constexpr inline size_t getRowSize() const { return BASE::ROW_SIZE; } + constexpr inline size_t getColumnCount() const { return BASE::NUM_COLS; } + constexpr inline size_t getRowCount() const { return BASE::NUM_ROWS; } + constexpr inline size_t size() const { return BASE::ROW_SIZE; } // for TVec*<> + + // array access + constexpr T const* asArray() const { + return &static_cast const &>(*this)[0][0]; + } + + // element access + inline constexpr T const& operator()(size_t row, size_t col) const { + return static_cast const &>(*this)[col][row]; + } + + inline T& operator()(size_t row, size_t col) { + return static_cast&>(*this)[col][row]; + } + +private: + constexpr friend inline BASE MATH_PURE abs(BASE m) { + for (size_t col = 0; col < BASE::NUM_COLS; ++col) { + m[col] = abs(m[col]); + } + return m; + } +}; + +// functions for 3x3 and 4x4 matrices +template class BASE, typename T> +class TMatTransform { +public: + inline constexpr TMatTransform() { + static_assert(BASE::NUM_ROWS == 3 || BASE::NUM_ROWS == 4, "3x3 or 4x4 matrices only"); + } + + template> + static BASE rotation(A radian, VEC about) { + BASE r; + T c = std::cos(radian); + T s = std::sin(radian); + if (about[0] == 1 && about[1] == 0 && about[2] == 0) { + r[1][1] = c; r[2][2] = c; + r[1][2] = s; r[2][1] = -s; + } else if (about[0] == 0 && about[1] == 1 && about[2] == 0) { + r[0][0] = c; r[2][2] = c; + r[2][0] = s; r[0][2] = -s; + } else if (about[0] == 0 && about[1] == 0 && about[2] == 1) { + r[0][0] = c; r[1][1] = c; + r[0][1] = s; r[1][0] = -s; + } else { + VEC nabout = normalize(about); + typename VEC::value_type x = nabout[0]; + typename VEC::value_type y = nabout[1]; + typename VEC::value_type z = nabout[2]; + T nc = 1 - c; + T xy = x * y; + T yz = y * z; + T zx = z * x; + T xs = x * s; + T ys = y * s; + T zs = z * s; + r[0][0] = x*x*nc + c; r[1][0] = xy*nc - zs; r[2][0] = zx*nc + ys; + r[0][1] = xy*nc + zs; r[1][1] = y*y*nc + c; r[2][1] = yz*nc - xs; + r[0][2] = zx*nc - ys; r[1][2] = yz*nc + xs; r[2][2] = z*z*nc + c; + + // Clamp results to -1, 1. + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1)); + } + } + } + return r; + } + + /** + * Create a matrix from euler angles using YPR around YXZ respectively + * @param yaw about Y axis + * @param pitch about X axis + * @param roll about Z axis + */ + template> + static BASE eulerYXZ(Y yaw, P pitch, R roll) { + return eulerZYX(roll, pitch, yaw); + } + + /** + * Create a matrix from euler angles using YPR around ZYX respectively + * @param roll about X axis + * @param pitch about Y axis + * @param yaw about Z axis + * + * The euler angles are applied in ZYX order. i.e: a vector is first rotated + * about X (roll) then Y (pitch) and then Z (yaw). + */ + template> + static BASE eulerZYX(Y yaw, P pitch, R roll) { + BASE r; + T cy = std::cos(yaw); + T sy = std::sin(yaw); + T cp = std::cos(pitch); + T sp = std::sin(pitch); + T cr = std::cos(roll); + T sr = std::sin(roll); + T cc = cr * cy; + T cs = cr * sy; + T sc = sr * cy; + T ss = sr * sy; + r[0][0] = cp * cy; + r[0][1] = cp * sy; + r[0][2] = -sp; + r[1][0] = sp * sc - cs; + r[1][1] = sp * ss + cc; + r[1][2] = cp * sr; + r[2][0] = sp * cc + ss; + r[2][1] = sp * cs - sc; + r[2][2] = cp * cr; + + // Clamp results to -1, 1. + for (size_t col = 0; col < 3; ++col) { + for (size_t row = 0; row < 3; ++row) { + r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1)); + } + } + return r; + } + + TQuaternion toQuaternion() const { + return matrix::extractQuat(static_cast&>(*this)); + } +}; + +// ------------------------------------------------------------------------------------- +} // namespace details +} // namespace math +} // namespace filament + +#endif // TNT_MATH_TMATHELPERS_H diff --git a/package/ios/libs/filament/include/math/TQuatHelpers.h b/package/ios/libs/filament/include/math/TQuatHelpers.h new file mode 100644 index 00000000..0439b971 --- /dev/null +++ b/package/ios/libs/filament/include/math/TQuatHelpers.h @@ -0,0 +1,294 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TQUATHELPERS_H +#define TNT_MATH_TQUATHELPERS_H + +#include +#include +#include + +#include +#include +#include + +namespace filament::math::details { + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/quat.h + */ + + +/* + * TQuatProductOperators implements basic arithmetic and basic compound assignment + * operators on a quaternion of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TQuatProductOperators BASE will automatically + * get all the functionality here. + */ + +template class QUATERNION, typename T> +class TQuatProductOperators { +public: + /* compound assignment from another quaternion of the same size but different + * element type. + */ + template + constexpr QUATERNION& operator*=(const QUATERNION& r) { + QUATERNION& q = static_cast&>(*this); + q = q * r; + return q; + } + + /* compound assignment products by a scalar + */ + template>> + constexpr QUATERNION& operator*=(U v) { + QUATERNION& lhs = static_cast&>(*this); + for (size_t i = 0; i < QUATERNION::size(); i++) { + lhs[i] *= v; + } + return lhs; + } + + template>> + constexpr QUATERNION& operator/=(U v) { + QUATERNION& lhs = static_cast&>(*this); + for (size_t i = 0; i < QUATERNION::size(); i++) { + lhs[i] /= v; + } + return lhs; + } + + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + /* The operators below handle operation between quaternions of the same size + * but of a different element type. + */ + template + friend inline constexpr + QUATERNION> MATH_PURE operator*( + const QUATERNION& q, const QUATERNION& r) { + // could be written as: + // return QUATERNION( + // q.w*r.w - dot(q.xyz, r.xyz), + // q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz)); + return { + q.w * r.w - q.x * r.x - q.y * r.y - q.z * r.z, + q.w * r.x + q.x * r.w + q.y * r.z - q.z * r.y, + q.w * r.y - q.x * r.z + q.y * r.w + q.z * r.x, + q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w + }; + } + + template + friend inline constexpr + TVec3> MATH_PURE operator*(const QUATERNION& q, const TVec3& v) { + // note: if q is known to be a unit quaternion, then this simplifies to: + // TVec3 t = 2 * cross(q.xyz, v) + // return v + (q.w * t) + cross(q.xyz, t) + return imaginary(q * QUATERNION(v, 0) * inverse(q)); + } + + + /* For quaternions, we use explicit "by a scalar" products because it's much faster + * than going (implicitly) through the quaternion multiplication. + * For reference: we could use the code below instead, but it would be a lot slower. + * friend inline + * constexpr BASE MATH_PURE operator *(const BASE& q, const BASE& r) { + * return BASE( + * q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z, + * q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y, + * q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x, + * q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w); + * + */ + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator*(QUATERNION q, U scalar) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q *= scalar); + } + + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator*(U scalar, QUATERNION q) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q *= scalar); + } + + template>> + friend inline constexpr + QUATERNION> MATH_PURE operator/(QUATERNION q, U scalar) { + // don't pass q by reference because we need a copy anyway + return QUATERNION>(q /= scalar); + } +}; + + +/* + * TQuatFunctions implements functions on a quaternion of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TQuatFunctions BASE will automatically + * get all the functionality here. + */ +template class QUATERNION, typename T> +class TQuatFunctions { +public: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + arithmetic_result_t MATH_PURE dot( + const QUATERNION& p, const QUATERNION& q) { + return p.x * q.x + + p.y * q.y + + p.z * q.z + + p.w * q.w; + } + + friend inline + T MATH_PURE norm(const QUATERNION& q) { + return std::sqrt(dot(q, q)); + } + + friend inline + T MATH_PURE length(const QUATERNION& q) { + return norm(q); + } + + friend inline + constexpr T MATH_PURE length2(const QUATERNION& q) { + return dot(q, q); + } + + friend inline + QUATERNION MATH_PURE normalize(const QUATERNION& q) { + return length(q) ? q / length(q) : QUATERNION(static_cast(1)); + } + + friend inline + constexpr QUATERNION MATH_PURE conj(const QUATERNION& q) { + return QUATERNION(q.w, -q.x, -q.y, -q.z); + } + + friend inline + constexpr QUATERNION MATH_PURE inverse(const QUATERNION& q) { + return conj(q) * (T(1) / dot(q, q)); + } + + friend inline + constexpr T MATH_PURE real(const QUATERNION& q) { + return q.w; + } + + friend inline + constexpr TVec3 MATH_PURE imaginary(const QUATERNION& q) { + return q.xyz; + } + + friend inline + constexpr QUATERNION MATH_PURE unreal(const QUATERNION& q) { + return QUATERNION(q.xyz, 0); + } + + template + friend inline constexpr + QUATERNION> MATH_PURE cross( + const QUATERNION& p, const QUATERNION& q) { + return unreal(p * q); + } + + friend inline + QUATERNION MATH_PURE exp(const QUATERNION& q) { + const T nq(norm(q.xyz)); + return std::exp(q.w) * QUATERNION((sin(nq) / nq) * q.xyz, cos(nq)); + } + + friend inline + QUATERNION MATH_PURE log(const QUATERNION& q) { + const T nq(norm(q)); + return QUATERNION((std::acos(q.w / nq) / norm(q.xyz)) * q.xyz, std::log(nq)); + } + + friend inline + QUATERNION MATH_PURE pow(const QUATERNION& q, T a) { + // could also be computed as: exp(a*log(q)); + const T nq(norm(q)); + const T theta(a * std::acos(q.w / nq)); + return std::pow(nq, a) * QUATERNION(normalize(q.xyz) * std::sin(theta), std::cos(theta)); + } + + friend inline + QUATERNION MATH_PURE slerp(const QUATERNION& p, const QUATERNION& q, T t) { + // could also be computed as: pow(q * inverse(p), t) * p; + const T d = dot(p, q); + const T absd = std::abs(d); + static constexpr T value_eps = T(10) * std::numeric_limits::epsilon(); + // Prevent blowing up when slerping between two quaternions that are very near each other. + if ((T(1) - absd) < value_eps) { + return normalize(lerp(d < 0 ? -p : p, q, t)); + } + const T npq = std::sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q|| + const T a = std::acos(filament::math::clamp(absd / npq, T(-1), T(1))); + const T a0 = a * (1 - t); + const T a1 = a * t; + const T sina = sin(a); + if (sina < value_eps) { + return normalize(lerp(p, q, t)); + } + const T isina = 1 / sina; + const T s0 = std::sin(a0) * isina; + const T s1 = std::sin(a1) * isina; + // ensure we're taking the "short" side + return normalize(s0 * p + ((d < 0) ? (-s1) : (s1)) * q); + } + + friend inline + constexpr QUATERNION MATH_PURE lerp(const QUATERNION& p, const QUATERNION& q, T t) { + return ((1 - t) * p) + (t * q); + } + + friend inline + constexpr QUATERNION MATH_PURE nlerp(const QUATERNION& p, const QUATERNION& q, T t) { + return normalize(lerp(p, q, t)); + } + + friend inline + constexpr QUATERNION MATH_PURE positive(const QUATERNION& q) { + return q.w < 0 ? -q : q; + } +}; + +} // namespace filament::math::details + +#endif // TNT_MATH_TQUATHELPERS_H diff --git a/package/ios/libs/filament/include/math/TVecHelpers.h b/package/ios/libs/filament/include/math/TVecHelpers.h new file mode 100644 index 00000000..fb7d026d --- /dev/null +++ b/package/ios/libs/filament/include/math/TVecHelpers.h @@ -0,0 +1,654 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_TVECHELPERS_H +#define TNT_MATH_TVECHELPERS_H + +#include + +#include // for std:: namespace + +#include +#include + +namespace filament::math::details { + +template +inline constexpr U min(U a, U b) noexcept { + return a < b ? a : b; +} + +template +inline constexpr U max(U a, U b) noexcept { + return a > b ? a : b; +} + +template +struct arithmetic_result { + using type = decltype(std::declval() + std::declval()); +}; + +template +using arithmetic_result_t = typename arithmetic_result::type; + +template +using enable_if_arithmetic_t = std::enable_if_t< + is_arithmetic
::value && + is_arithmetic::value && + is_arithmetic::value && + is_arithmetic::value>; + +/* + * No user serviceable parts here. + * + * Don't use this file directly, instead include math/vec{2|3|4}.h + */ + +/* + * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments + * operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVec{Add|Product}Operators BASE will automatically + * get all the functionality here. + */ + +template class VECTOR, typename T> +class TVecAddOperators { +public: + /* compound assignment from a another vector of the same size but different + * element type. + */ + template + constexpr VECTOR& operator+=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] += v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator+=(U v) { + return operator+=(VECTOR(v)); + } + + template + constexpr VECTOR& operator-=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] -= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator-=(U v) { + return operator-=(VECTOR(v)); + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + VECTOR> MATH_PURE operator+(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res += rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator+(const VECTOR& lv, U rv) { + return lv + VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator+(U lv, const VECTOR& rv) { + return VECTOR(lv) + rv; + } + + template + friend inline constexpr + VECTOR> MATH_PURE operator-(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res -= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator-(const VECTOR& lv, U rv) { + return lv - VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator-(U lv, const VECTOR& rv) { + return VECTOR(lv) - rv; + } +}; + +template class VECTOR, typename T> +class TVecProductOperators { +public: + /* compound assignment from a another vector of the same size but different + * element type. + */ + template + constexpr VECTOR& operator*=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] *= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator*=(U v) { + return operator*=(VECTOR(v)); + } + + template + constexpr VECTOR& operator/=(const VECTOR& v) { + VECTOR& lhs = static_cast&>(*this); + for (size_t i = 0; i < lhs.size(); i++) { + lhs[i] /= v[i]; + } + return lhs; + } + + template> + constexpr VECTOR& operator/=(U v) { + return operator/=(VECTOR(v)); + } + +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + + template + friend inline constexpr + VECTOR> MATH_PURE operator*(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res *= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator*(const VECTOR& lv, U rv) { + return lv * VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator*(U lv, const VECTOR& rv) { + return VECTOR(lv) * rv; + } + + template + friend inline constexpr + VECTOR> MATH_PURE operator/(const VECTOR& lv, const VECTOR& rv) { + VECTOR> res(lv); + res /= rv; + return res; + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator/(const VECTOR& lv, U rv) { + return lv / VECTOR(rv); + } + + template> + friend inline constexpr + VECTOR> MATH_PURE operator/(U lv, const VECTOR& rv) { + return VECTOR(lv) / rv; + } +}; + +/* + * TVecUnaryOperators implements unary operators on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecUnaryOperators BASE will automatically + * get all the functionality here. + * + * These operators are implemented as friend functions of TVecUnaryOperators + */ +template class VECTOR, typename T> +class TVecUnaryOperators { +public: + constexpr VECTOR operator-() const { + VECTOR r{}; + VECTOR const& rv(static_cast const&>(*this)); + for (size_t i = 0; i < r.size(); i++) { + r[i] = -rv[i]; + } + return r; + } +}; + +/* + * TVecComparisonOperators implements relational/comparison operators + * on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecComparisonOperators BASE will automatically + * get all the functionality here. + */ +template class VECTOR, typename T> +class TVecComparisonOperators { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend inline constexpr + bool MATH_PURE operator==(const VECTOR& lv, const VECTOR& rv) { + for (size_t i = 0; i < lv.size(); i++) { + if (lv[i] != rv[i]) { + return false; + } + } + return true; + } + + template + friend inline constexpr + bool MATH_PURE operator!=(const VECTOR& lv, const VECTOR& rv) { + return !operator==(lv, rv); + } + + template + friend inline constexpr + VECTOR MATH_PURE equal(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] == rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE notEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] != rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE lessThan(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] < rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE lessThanEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] <= rv[i]; + } + return r; + } + + template + friend inline constexpr + VECTOR MATH_PURE greaterThan(const VECTOR& lv, const VECTOR& rv) { + VECTOR r; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] > rv[i]; + } + return r; + } + + template + friend inline + VECTOR MATH_PURE greaterThanEqual(const VECTOR& lv, const VECTOR& rv) { + VECTOR r{}; + for (size_t i = 0; i < lv.size(); i++) { + r[i] = lv[i] >= rv[i]; + } + return r; + } +}; + +/* + * TVecFunctions implements functions on a vector of type BASE. + * + * BASE only needs to implement operator[] and size(). + * By simply inheriting from TVecFunctions BASE will automatically + * get all the functionality here. + */ +template class VECTOR, typename T> +class TVecFunctions { +private: + /* + * NOTE: the functions below ARE NOT member methods. They are friend functions + * with they definition inlined with their declaration. This makes these + * template functions available to the compiler when (and only when) this class + * is instantiated, at which point they're only templated on the 2nd parameter + * (the first one, BASE being known). + */ + template + friend constexpr inline + arithmetic_result_t MATH_PURE dot(const VECTOR& lv, const VECTOR& rv) { + arithmetic_result_t r{}; + for (size_t i = 0; i < lv.size(); i++) { + r += lv[i] * rv[i]; + } + return r; + } + + friend inline T MATH_PURE norm(const VECTOR& lv) { + return std::sqrt(dot(lv, lv)); + } + + friend inline T MATH_PURE length(const VECTOR& lv) { + return norm(lv); + } + + friend inline constexpr T MATH_PURE norm2(const VECTOR& lv) { + return dot(lv, lv); + } + + friend inline constexpr T MATH_PURE length2(const VECTOR& lv) { + return norm2(lv); + } + + template + friend inline constexpr + arithmetic_result_t MATH_PURE distance(const VECTOR& lv, const VECTOR& rv) { + return length(rv - lv); + } + + template + friend inline constexpr + arithmetic_result_t MATH_PURE distance2(const VECTOR& lv, const VECTOR& rv) { + return length2(rv - lv); + } + + friend inline VECTOR MATH_PURE normalize(const VECTOR& lv) { + return lv * (T(1) / length(lv)); + } + + friend inline VECTOR MATH_PURE rcp(VECTOR v) { + return T(1) / v; + } + + friend inline constexpr VECTOR MATH_PURE abs(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < 0 ? -v[i] : v[i]; + } + return v; + } + + friend inline VECTOR MATH_PURE floor(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::floor(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE ceil(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::ceil(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE round(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::round(v[i]); + } + return v; + } + + template + friend inline + VECTOR MATH_PURE fmod(VECTOR const& x, VECTOR const& y) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::fmod(x[i], y[i]); + } + return r; + } + + template + friend inline + VECTOR MATH_PURE remainder(VECTOR const& x, VECTOR const& y) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::remainder(x[i], y[i]); + } + return r; + } + + template + friend inline + VECTOR MATH_PURE remquo(VECTOR const& x, VECTOR const& y, + VECTOR* q) { + VECTOR r; + for (size_t i = 0; i < r.size(); i++) { + r[i] = std::remquo(x[i], y[i], &((*q)[i])); + } + return r; + } + + friend inline VECTOR MATH_PURE inversesqrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = T(1) / std::sqrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE sqrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::sqrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE cbrt(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::cbrt(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE exp(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::exp(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE sign(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::copysign(T(1), v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE pow(VECTOR v, T p) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::pow(v[i], p); + } + return v; + } + + friend inline VECTOR MATH_PURE pow(T v, VECTOR p) { + for (size_t i = 0; i < p.size(); i++) { + p[i] = std::pow(v, p[i]); + } + return p; + } + + friend inline VECTOR MATH_PURE pow(VECTOR v, VECTOR p) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::pow(v[i], p[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log10(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log10(v[i]); + } + return v; + } + + friend inline VECTOR MATH_PURE log2(VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = std::log2(v[i]); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE saturate(const VECTOR& lv) { + return clamp(lv, T(0), T(1)); + } + + friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, T min, T max) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(max, details::max(min, v[i])); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, VECTOR min, VECTOR max) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(max[i], details::max(min[i], v[i])); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE fma(const VECTOR& lv, const VECTOR& rv, + VECTOR a) { + for (size_t i = 0; i < lv.size(); i++) { + a[i] += (lv[i] * rv[i]); + } + return a; + } + + friend inline constexpr VECTOR MATH_PURE min(const VECTOR& u, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::min(u[i], v[i]); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE max(const VECTOR& u, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = details::max(u[i], v[i]); + } + return v; + } + + friend inline constexpr T MATH_PURE max(const VECTOR& v) { + T r(v[0]); + for (size_t i = 1; i < v.size(); i++) { + r = max(r, v[i]); + } + return r; + } + + friend inline constexpr T MATH_PURE min(const VECTOR& v) { + T r(v[0]); + for (size_t i = 1; i < v.size(); i++) { + r = min(r, v[i]); + } + return r; + } + + friend inline constexpr VECTOR MATH_PURE mix(const VECTOR& u, VECTOR v, T a) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = u[i] * (T(1) - a) + v[i] * a; + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE smoothstep(T edge0, T edge1, VECTOR v) { + VECTOR t = saturate((v - edge0) / (edge1 - edge0)); + return t * t * (T(3) - T(2) * t); + } + + friend inline constexpr VECTOR MATH_PURE step(T edge, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < edge ? T(0) : T(1); + } + return v; + } + + friend inline constexpr VECTOR MATH_PURE step(VECTOR edge, VECTOR v) { + for (size_t i = 0; i < v.size(); i++) { + v[i] = v[i] < edge[i] ? T(0) : T(1); + } + return v; + } + + friend inline constexpr bool MATH_PURE any(const VECTOR& v) { + for (size_t i = 0; i < v.size(); i++) { + if (v[i] != T(0)) return true; + } + return false; + } + + friend inline constexpr bool MATH_PURE all(const VECTOR& v) { + bool result = true; + for (size_t i = 0; i < v.size(); i++) { + result &= (v[i] != T(0)); + } + return result; + } +}; + +} // namespace filament::math::details + +#endif // TNT_MATH_TVECHELPERS_H diff --git a/package/ios/libs/filament/include/math/compiler.h b/package/ios/libs/filament/include/math/compiler.h new file mode 100644 index 00000000..634e2077 --- /dev/null +++ b/package/ios/libs/filament/include/math/compiler.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_MATH_COMPILER_H +#define TNT_MATH_COMPILER_H + +#include + +#if defined (WIN32) + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#ifdef far +#undef far +#endif + +#ifdef near +#undef near +#endif + +#endif + +// compatibility with non-clang compilers... +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__builtin_expect) +# ifdef __cplusplus +# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +# else +# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +# endif +#else +# define MATH_LIKELY( exp ) (exp) +# define MATH_UNLIKELY( exp ) (exp) +#endif + +#if __has_attribute(unused) +# define MATH_UNUSED __attribute__((unused)) +#else +# define MATH_UNUSED +#endif + +#if __has_attribute(pure) +# define MATH_PURE __attribute__((pure)) +#else +# define MATH_PURE +#endif + +#ifdef _MSC_VER +# define MATH_EMPTY_BASES __declspec(empty_bases) + +// MSVC does not support loop unrolling hints +# define MATH_NOUNROLL + +// Sadly, MSVC does not support __builtin_constant_p +# ifndef MAKE_CONSTEXPR +# define MAKE_CONSTEXPR(e) (e) +# endif + +// About value initialization, the C++ standard says: +// if T is a class type with a default constructor that is neither user-provided nor deleted +// (that is, it may be a class with an implicitly-defined or defaulted default constructor), +// the object is zero-initialized and then it is default-initialized +// if it has a non-trivial default constructor; +// Unfortunately, MSVC always calls the default constructor, even if it is trivial, which +// breaks constexpr-ness. To workaround this, we're always zero-initializing TVecN<> +# define MATH_CONSTEXPR_INIT {} +# define MATH_DEFAULT_CTOR {} +# define MATH_DEFAULT_CTOR_CONSTEXPR constexpr +# define CONSTEXPR_IF_NOT_MSVC // when declared constexpr, msvc fails with "failure was caused by cast of object of dynamic type" + +#else // _MSC_VER + +# define MATH_EMPTY_BASES +// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax. +# define MATH_NOUNROLL _Pragma("nounroll") + +# ifndef MAKE_CONSTEXPR +# define MAKE_CONSTEXPR(e) __builtin_constant_p(e) ? (e) : (e) +# endif + +# define MATH_CONSTEXPR_INIT +# define MATH_DEFAULT_CTOR = default; +# define MATH_DEFAULT_CTOR_CONSTEXPR +# define CONSTEXPR_IF_NOT_MSVC constexpr + +#endif // _MSC_VER + +namespace filament::math { + +// MSVC 2019 16.4 doesn't seem to like it when we specialize std::is_arithmetic for +// filament::math::half, so we're forced to create our own is_arithmetic here and specialize it +// inside of half.h. +template +struct is_arithmetic : std::integral_constant::value || std::is_floating_point::value> { +}; + +} // filament::math + +#endif // TNT_MATH_COMPILER_H diff --git a/package/ios/libs/filament/include/math/fast.h b/package/ios/libs/filament/include/math/fast.h new file mode 100644 index 00000000..85b990d2 --- /dev/null +++ b/package/ios/libs/filament/include/math/fast.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_FAST_H +#define TNT_MATH_FAST_H + +#include +#include + +#include +#include + +#include + +#ifdef __ARM_NEON +#include +#endif + +namespace filament { +namespace math { +namespace fast { + +// fast cos(x), ~8 cycles (vs. 66 cycles on ARM) +// can be vectorized +// x between -pi and pi +template::value>> +constexpr T MATH_PURE cos(T x) noexcept { + x *= T(F_1_PI / 2); + x -= T(0.25) + std::floor(x + T(0.25)); + x *= T(16.0) * std::abs(x) - T(8.0); + x += T(0.225) * x * (std::abs(x) - T(1.0)); + return x; +} + +// fast sin(x), ~8 cycles (vs. 66 cycles on ARM) +// can be vectorized +// x between -pi and pi +template::value>> +constexpr T MATH_PURE sin(T x) noexcept { + return filament::math::fast::cos(x - T(F_PI_2)); +} + +constexpr inline float MATH_PURE ilog2(float x) noexcept { + union { + float val; + int32_t x; + } u = { x }; + return float(((u.x >> 23) & 0xff) - 127); +} + +constexpr inline float MATH_PURE log2(float x) noexcept { + union { + float val; + int32_t x; + } u = { x }; + float ilog2 = float(((u.x >> 23) & 0xff) - 128); + u.x = (u.x & 0x007fffff) | 0x3f800000; + return ilog2 + (-0.34484843f * u.val + 2.02466578f) * u.val - 0.67487759f; +} + +// fast 1/sqrt(), on ARMv8 this is 5 cycles vs. 7 cycles, so maybe not worth it. +// we keep this mostly for reference and benchmarking. +inline float MATH_PURE isqrt(float x) noexcept { +#if defined(__ARM_NEON) && defined(__aarch64__) + float y = vrsqrtes_f32(x); + return y * vrsqrtss_f32(x, y * y); +#else + return 1 / std::sqrt(x); +#endif +} + +inline double MATH_PURE isqrt(double x) noexcept { +#if defined(__ARM_NEON) && defined(__aarch64__) + double y = vrsqrted_f64(x); + return y * vrsqrtsd_f64(x, y * y); +#else + return 1 / std::sqrt(x); +#endif +} + +inline int signbit(float x) noexcept { +#if __has_builtin(__builtin_signbitf) + // Note: on Android NDK, signbit() is a function call -- not what we want. + return __builtin_signbitf(x); +#else + return std::signbit(x); +#endif +} + +/* + * constexpr exp(), pow(), factorial() + */ + +constexpr double pow(double x, unsigned int y) noexcept { + return y == 0 ? 1.0 : x * pow(x, y - 1); +} + +constexpr unsigned int factorial(unsigned int x) noexcept { + return x == 0 ? 1 : x * factorial(x - 1); +} + +constexpr double exp(double x) noexcept { + return 1.0 + x + pow(x, 2) / factorial(2) + pow(x, 3) / factorial(3) + + pow(x, 4) / factorial(4) + pow(x, 5) / factorial(5) + + pow(x, 6) / factorial(6) + pow(x, 7) / factorial(7) + + pow(x, 8) / factorial(8) + pow(x, 9) / factorial(9); +} + +constexpr float exp(float x) noexcept { + return float(exp(double(x))); +} + +/* + * unsigned saturated arithmetic + */ + +#if defined(__ARM_NEON) && defined(__aarch64__) +inline uint8_t MATH_PURE qadd(uint8_t a, uint8_t b) noexcept { return vuqaddb_s8(a, b); } +inline uint16_t MATH_PURE qadd(uint16_t a, uint16_t b) noexcept { return vuqaddh_s16(a, b); } +inline uint32_t MATH_PURE qadd(uint32_t a, uint32_t b) noexcept { return vuqadds_s32(a, b); } + +inline uint8_t MATH_PURE qsub(uint8_t a, uint8_t b) noexcept { return vqsubb_s8(a, b); } +inline uint16_t MATH_PURE qsub(uint16_t a, uint16_t b) noexcept { return vqsubh_s16(a, b); } +inline uint32_t MATH_PURE qsub(uint32_t a, uint32_t b) noexcept { return vqsubs_s32(a, b); } +#else + +template::value || + std::is_same::value || + std::is_same::value>> +inline T MATH_PURE qadd(T a, T b) noexcept { + T r = a + b; + return r | -T(r < a); +} + +template::value || + std::is_same::value || + std::is_same::value>> +inline T MATH_PURE qsub(T a, T b) noexcept { + T r = a - b; + return r & -T(r <= a); +} + +#endif + +template +inline T MATH_PURE qinc(T a) noexcept { + return qadd(a, T(1)); +} + +template +inline T MATH_PURE qdec(T a) noexcept { + return qsub(a, T(1)); +} + + +} // namespace fast +} // namespace math +} // namespace filament + +#endif // TNT_MATH_FAST_H diff --git a/package/ios/libs/filament/include/math/half.h b/package/ios/libs/filament/include/math/half.h new file mode 100644 index 00000000..d792e1bf --- /dev/null +++ b/package/ios/libs/filament/include/math/half.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_HALF_H +#define TNT_MATH_HALF_H + +#include + +#include +#include + +#include +#include + +namespace filament { +namespace math { + +template +class fp { + static_assert(S + E + M <= 16, "we only support 16-bits max custom floats"); + + using TYPE = uint16_t; // this should be dynamic + + static constexpr unsigned S_SHIFT = E + M; + static constexpr unsigned E_SHIFT = M; + static constexpr unsigned M_SHIFT = 0; + static constexpr unsigned S_MASK = ((1u << S) - 1u) << S_SHIFT; + static constexpr unsigned E_MASK = ((1u << E) - 1u) << E_SHIFT; + static constexpr unsigned M_MASK = ((1u << M) - 1u) << M_SHIFT; + + struct fp32 { + explicit constexpr fp32(float f) noexcept : fp(f) { } // NOLINT + explicit constexpr fp32(uint32_t b) noexcept : bits(b) { } // NOLINT + constexpr void setS(unsigned int s) noexcept { + bits = uint32_t((bits & 0x7FFFFFFFu) | (s << 31u)); + } + constexpr unsigned int getS() const noexcept { return bits >> 31u; } + constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; } + constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; } + union { + uint32_t bits; + float fp; + }; + }; + +public: + static constexpr fp fromf(float f) noexcept { + fp out; + if (S == 0 && f < 0.0f) { + return out; + } + + fp32 in(f); + unsigned int sign = in.getS(); + in.setS(0); + if (MATH_UNLIKELY(in.getE() == 0xFF)) { // inf or nan + out.setE((1u << E) - 1u); + out.setM(in.getM() ? (1u << (M - 1u)) : 0); + } else { + constexpr fp32 infinity(((1u << E) - 1u) << 23u); // fp infinity in fp32 position + constexpr fp32 magic(((1u << (E - 1u)) - 1u) << 23u); // exponent offset + in.bits &= ~((1u << (22 - M)) - 1u); // erase extra mantissa bits + in.bits += 1u << (22 - M); // rounding + in.fp *= magic.fp; // add exponent offset + in.bits = in.bits < infinity.bits ? in.bits : infinity.bits; + out.bits = uint16_t(in.bits >> (23 - M)); + } + out.setS(sign); + return out; + } + + static constexpr float tof(fp in) noexcept { + constexpr fp32 magic ((0xFE - ((1u << (E - 1u)) - 1u)) << 23u); + constexpr fp32 infnan((0x80 + ((1u << (E - 1u)) - 1u)) << 23u); + fp32 out((in.bits & ((1u << (E + M)) - 1u)) << (23u - M)); + out.fp *= magic.fp; + if (out.fp >= infnan.fp) { + out.bits |= 0xFFu << 23u; + } + out.bits |= (in.bits & S_MASK) << (31u - S_SHIFT); + return out.fp; + } + + TYPE bits{}; + static constexpr size_t getBitCount() noexcept { return S + E + M; } + constexpr fp() noexcept = default; + explicit constexpr fp(TYPE bits) noexcept : bits(bits) { } + constexpr void setS(unsigned int s) noexcept { bits = TYPE((bits & ~S_MASK) | (s << S_SHIFT)); } + constexpr void setE(unsigned int s) noexcept { bits = TYPE((bits & ~E_MASK) | (s << E_SHIFT)); } + constexpr void setM(unsigned int s) noexcept { bits = TYPE((bits & ~M_MASK) | (s << M_SHIFT)); } + constexpr unsigned int getS() const noexcept { return (bits & S_MASK) >> S_SHIFT; } + constexpr unsigned int getE() const noexcept { return (bits & E_MASK) >> E_SHIFT; } + constexpr unsigned int getM() const noexcept { return (bits & M_MASK) >> M_SHIFT; } +}; + +/* + * half-float + * + * 1 5 10 + * +-+------+------------+ + * |s|eee.ee|mm.mmmm.mmmm| + * +-+------+------------+ + * + * minimum (denormal) value: 2^-24 = 5.96e-8 + * minimum (normal) value: 2^-14 = 6.10e-5 + * maximum value: (2 - 2^-10) * 2^15 = 65504 + * + * Integers between 0 and 2048 can be represented exactly + */ + +#ifdef __ARM_NEON + +using half = __fp16; + +inline constexpr uint16_t getBits(half const& h) noexcept { + return MAKE_CONSTEXPR(reinterpret_cast(h)); +} + +inline constexpr half makeHalf(uint16_t bits) noexcept { + return MAKE_CONSTEXPR(reinterpret_cast(bits)); +} + +#else + +class half { + using fp16 = fp<1, 5, 10>; + +public: + half() = default; + constexpr half(float v) noexcept : mBits(fp16::fromf(v)) { } // NOLINT + constexpr operator float() const noexcept { return fp16::tof(mBits); } // NOLINT + +private: + // these are friends, not members (and they're not "private") + friend constexpr uint16_t getBits(half const& h) noexcept { return h.mBits.bits; } + friend constexpr inline half makeHalf(uint16_t bits) noexcept; + + enum Binary { binary }; + explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { } + + fp16 mBits; +}; + +constexpr inline half makeHalf(uint16_t bits) noexcept { + return half(half::binary, bits); +} + +#endif // __ARM_NEON + +inline constexpr half operator""_h(long double v) { + return half( static_cast(v) ); +} + +template<> struct is_arithmetic : public std::true_type {}; + +} // namespace math +} // namespace filament + +namespace std { + +template<> struct is_floating_point : public std::true_type {}; + +// note: this shouldn't be needed (is_floating_point<> is enough) but some version of msvc need it +// This stopped working with MSVC 2019 16.4, so we specialize our own version of is_arithmetic in +// the math::filament namespace (see above). +template<> struct is_arithmetic : public std::true_type {}; + +template<> +class numeric_limits { +public: + typedef filament::math::half type; + + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool has_infinity = true; + static constexpr const bool has_quiet_NaN = true; + static constexpr const bool has_signaling_NaN = false; + static constexpr const float_denorm_style has_denorm = denorm_absent; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const float_round_style round_style = round_indeterminate; + + static constexpr const int digits = 11; + static constexpr const int digits10 = 3; + static constexpr const int max_digits10 = 5; + static constexpr const int radix = 2; + static constexpr const int min_exponent = -13; + static constexpr const int min_exponent10 = -4; + static constexpr const int max_exponent = 16; + static constexpr const int max_exponent10 = 4; + + inline static constexpr type round_error() noexcept { return filament::math::makeHalf(0x3800); } + inline static constexpr type min() noexcept { return filament::math::makeHalf(0x0400); } + inline static constexpr type max() noexcept { return filament::math::makeHalf(0x7bff); } + inline static constexpr type lowest() noexcept { return filament::math::makeHalf(0xfbff); } + inline static constexpr type epsilon() noexcept { return filament::math::makeHalf(0x1400); } + inline static constexpr type infinity() noexcept { return filament::math::makeHalf(0x7c00); } + inline static constexpr type quiet_NaN() noexcept { return filament::math::makeHalf(0x7fff); } + inline static constexpr type denorm_min() noexcept { return filament::math::makeHalf(0x0001); } + inline static constexpr type signaling_NaN() noexcept { return filament::math::makeHalf(0x7dff); } +}; + +} // namespace std + +#endif // TNT_MATH_HALF_H diff --git a/package/ios/libs/filament/include/math/mat2.h b/package/ios/libs/filament/include/math/mat2.h new file mode 100644 index 00000000..dba9ca47 --- /dev/null +++ b/package/ios/libs/filament/include/math/mat2.h @@ -0,0 +1,347 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT2_H +#define TNT_MATH_MAT2_H + +#include +#include +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +/** + * A 2x2 column-major matrix class. + * + * Conceptually a 2x2 matrix is a an array of 2 column vec2: + * + * mat2 m = + * \f$ + * \left( + * \begin{array}{cc} + * m[0] & m[1] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cc} + * m[0][0] & m[1][0] \\ + * m[0][1] & m[1][1] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cc} + * m(0,0) & m(0,1) \\ + * m(1,0) & m(1,1) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec2. + * + */ +template +class MATH_EMPTY_BASES TMat22 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec2 col_type; + typedef TVec2 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /** + * constructors + */ + + /** + * leaves object uninitialized. use with caution. + */ + constexpr explicit TMat22(no_init) noexcept {} + + + /** + * initialize to identity. + * + * \f$ + * \left( + * \begin{array}{cc} + * 1 & 0 \\ + * 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat22() noexcept ; + + /** + * initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{cc} + * v & 0 \\ + * 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat22(U v) noexcept; + + /** + * sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{cc} + * v[0] & 0 \\ + * 0 & v[1] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat22(const TVec2& v) noexcept; + + /** + * construct from another matrix of the same size + */ + template + constexpr explicit TMat22(const TMat22& rhs) noexcept; + + /** + * construct from 2 column vectors. + * + * \f$ + * \left( + * \begin{array}{cc} + * v0 & v1 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat22(const TVec2& v0, const TVec2& v1) noexcept; + + /** construct from 4 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{cc} + * m[0][0] & m[1][0] \\ + * m[0][1] & m[1][1] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, + typename C, typename D> + constexpr explicit TMat22(A m00, B m01, C m10, D m11) noexcept ; + + + struct row_major_init { + template + constexpr explicit row_major_init(A m00, B m01, C m10, D m11) noexcept + : m(m00, m10, m01, m11) {} + + private: + friend TMat22; + TMat22 m; + }; + + constexpr explicit TMat22(row_major_init c) noexcept : TMat22(std::move(c.m)) {} + + /** + * Rotate by radians in the 2D plane + */ + static TMat22 rotate(T radian) noexcept { + TMat22 r(TMat22::NO_INIT); + T c = std::cos(radian); + T s = std::sin(radian); + r[0][0] = c; + r[1][1] = c; + r[0][1] = s; + r[1][0] = -s; + return r; + } + + template + static constexpr TMat22 translation(const TVec2& t) noexcept { + TMat22 r; + r[2] = t; + return r; + } + + template + static constexpr TMat22 scaling(const TVec2& s) noexcept { + return TMat22{ s }; + } + + template + static constexpr TMat22 scaling(A s) noexcept { + return TMat22{ TVec2{ s, s }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat22::TMat22() noexcept + : m_value{ col_type(1, 0), col_type(0, 1) } { +} + +template +template +constexpr TMat22::TMat22(U v) noexcept + : m_value{ col_type(v, 0), col_type(0, v) } { +} + +template +template +constexpr TMat22::TMat22(const TVec2& v) noexcept + : m_value{ col_type(v[0], 0), col_type(0, v[1]) } { +} + +// construct from 4 scalars. Note that the arrangement +// of values in the constructor is the transpose of the matrix +// notation. +template +template +constexpr TMat22::TMat22(A m00, B m01, C m10, D m11) noexcept + : m_value{ col_type(m00, m01), col_type(m10, m11) } { +} + +template +template +constexpr TMat22::TMat22(const TMat22& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 2 column vectors. +template +template +constexpr TMat22::TMat22(const TVec2& v0, const TVec2& v1) noexcept + : m_value{ v0, v1 } { +} + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat22 mat2; +typedef details::TMat22 mat2f; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat22& lhs, + filament::math::details::TMat22& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat22 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[1][0] = t10; + rhs[1][1] = t11; +} +} + +#endif // TNT_MATH_MAT2_H diff --git a/package/ios/libs/filament/include/math/mat3.h b/package/ios/libs/filament/include/math/mat3.h new file mode 100644 index 00000000..035865fe --- /dev/null +++ b/package/ios/libs/filament/include/math/mat3.h @@ -0,0 +1,540 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT3_H +#define TNT_MATH_MAT3_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +/** + * A 3x3 column-major matrix class. + * + * Conceptually a 3x3 matrix is a an array of 3 column vec3: + * + * mat3 m = + * \f$ + * \left( + * \begin{array}{ccc} + * m[0] & m[1] & m[2] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{ccc} + * m[0][0] & m[1][0] & m[2][0] \\ + * m[0][1] & m[1][1] & m[2][1] \\ + * m[0][2] & m[1][2] & m[2][2] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{ccc} + * m(0,0) & m(0,1) & m(0,2) \\ + * m(1,0) & m(1,1) & m(1,2) \\ + * m(2,0) & m(2,1) & m(2,2) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec3. + * + */ +template +class MATH_EMPTY_BASES TMat33 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatTransform, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec3 col_type; + typedef TVec3 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /** + * constructors + */ + + /** + * leaves object uninitialized. use with caution. + */ + constexpr explicit TMat33(no_init) noexcept {} + + + /** + * initialize to identity. + * + * \f$ + * \left( + * \begin{array}{ccc} + * 1 & 0 & 0 \\ + * 0 & 1 & 0 \\ + * 0 & 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat33() noexcept; + + /** + * initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v & 0 & 0 \\ + * 0 & v & 0 \\ + * 0 & 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat33(U v) noexcept; + + /** + * sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v[0] & 0 & 0 \\ + * 0 & v[1] & 0 \\ + * 0 & 0 & v[2] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat33(const TVec3& v) noexcept; + + /** + * construct from another matrix of the same size + */ + template + constexpr explicit TMat33(const TMat33& rhs) noexcept; + + /** + * construct from 3 column vectors. + * + * \f$ + * \left( + * \begin{array}{ccc} + * v0 & v1 & v2 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat33(const TVec3& v0, const TVec3& v1, const TVec3& v2) noexcept; + + /** construct from 9 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{ccc} + * m[0][0] & m[1][0] & m[2][0] \\ + * m[0][1] & m[1][1] & m[2][1] \\ + * m[0][2] & m[1][2] & m[2][2] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> + constexpr explicit TMat33(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept; + + + struct row_major_init { + template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> + constexpr explicit row_major_init(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept + : m(m00, m10, m20, + m01, m11, m21, + m02, m12, m22) {} + + private: + friend TMat33; + TMat33 m; + }; + + constexpr explicit TMat33(row_major_init c) noexcept : TMat33(std::move(c.m)) {} + + /** + * construct from a quaternion + */ + template + constexpr explicit TMat33(const TQuaternion& q) noexcept; + + /** + * orthogonalize only works on matrices of size 3x3 + */ + friend inline + constexpr TMat33 orthogonalize(const TMat33& m) noexcept { + TMat33 ret(TMat33::NO_INIT); + ret[0] = normalize(m[0]); + ret[2] = normalize(cross(ret[0], m[1])); + ret[1] = normalize(cross(ret[2], ret[0])); + return ret; + } + + /** + * Returns a matrix suitable for transforming normals + * + * Note that the inverse-transpose of a matrix is equal to its cofactor matrix divided by its + * determinant: + * + * transpose(inverse(M)) = cof(M) / det(M) + * + * The cofactor matrix is faster to compute than the inverse-transpose, and it can be argued + * that it is a more correct way of transforming normals anyway. Some references from Dale + * Weiler, Nathan Reed, Inigo Quilez, and Eric Lengyel: + * + * - https://github.com/graphitemaster/normals_revisited + * - http://www.reedbeta.com/blog/normals-inverse-transpose-part-1/ + * - https://www.shadertoy.com/view/3s33zj + * - FGED Volume 1, section 1.7.5 "Inverses of Small Matrices" + * - FGED Volume 1, section 3.2.2 "Transforming Normal Vectors" + * + * In "Transforming Normal Vectors", Lengyel notes that there are two types of transformed + * normals: one that uses the transposed adjugate (aka cofactor matrix) and one that uses the + * transposed inverse. He goes on to say that this difference is inconsequential, except when + * mirroring is involved. + * + * @param m the transform applied to vertices + * @return a matrix to apply to normals + * + * @warning normals transformed by this matrix must be normalized + */ + static constexpr TMat33 getTransformForNormals(const TMat33& m) noexcept { + return matrix::cof(m); + } + + /* + * Returns a matrix representing the pose of a virtual camera looking towards -Z in its + * local Y-up coordinate system. "up" defines where the Y axis of the camera's local coordinate + * system is. + */ + template + static TMat33 lookTo(const TVec3& direction, const TVec3& up) noexcept; + + /** + * Packs the tangent frame represented by the specified matrix into a quaternion. + * Reflection is preserved by encoding it as the sign of the w component in the + * resulting quaternion. Since -0 cannot always be represented on the GPU, this + * function computes a bias to ensure values are always either positive or negative, + * never 0. The bias is computed based on the specified storageSize, which defaults + * to 2 bytes, making the resulting quaternion suitable for storage into an SNORM16 + * vector. + */ + static constexpr TQuaternion packTangentFrame( + const TMat33& m, size_t storageSize = sizeof(int16_t)) noexcept; + + template + static constexpr TMat33 translation(const TVec3& t) noexcept { + TMat33 r; + r[2] = t; + return r; + } + + template + static constexpr TMat33 scaling(const TVec3& s) noexcept { + return TMat33{ s }; + } + + template + static constexpr TMat33 scaling(A s) noexcept { + return TMat33{ TVec3{ s }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat33::TMat33() noexcept + : m_value{ + col_type(1, 0, 0), + col_type(0, 1, 0), + col_type(0, 0, 1) } { +} + +template +template +constexpr TMat33::TMat33(U v) noexcept + : m_value{ + col_type(v, 0, 0), + col_type(0, v, 0), + col_type(0, 0, v) } { +} + +template +template +constexpr TMat33::TMat33(const TVec3& v) noexcept + : m_value{ + col_type(v[0], 0, 0), + col_type(0, v[1], 0), + col_type(0, 0, v[2]) } { +} + +// construct from 16 scalars. Note that the arrangement +// of values in the constructor is the transpose of the matrix +// notation. +template +template< + typename A, typename B, typename C, + typename D, typename E, typename F, + typename G, typename H, typename I> +constexpr TMat33::TMat33(A m00, B m01, C m02, + D m10, E m11, F m12, + G m20, H m21, I m22) noexcept + : m_value{ + col_type(m00, m01, m02), + col_type(m10, m11, m12), + col_type(m20, m21, m22) } { +} + +template +template +constexpr TMat33::TMat33(const TMat33& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 3 column vectors. +template +template +constexpr TMat33::TMat33(const TVec3& v0, const TVec3& v1, const TVec3& v2) noexcept + : m_value{ v0, v1, v2 } { +} + +template +template +constexpr TMat33::TMat33(const TQuaternion& q) noexcept : m_value{} { + const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + const U s = n > 0 ? 2 / n : 0; + const U x = s * q.x; + const U y = s * q.y; + const U z = s * q.z; + const U xx = x * q.x; + const U xy = x * q.y; + const U xz = x * q.z; + const U xw = x * q.w; + const U yy = y * q.y; + const U yz = y * q.z; + const U yw = y * q.w; + const U zz = z * q.z; + const U zw = z * q.w; + m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw); // NOLINT + m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw); // NOLINT + m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy); // NOLINT +} + +template +constexpr T dot_tolerance() noexcept; + +template<> +constexpr float dot_tolerance() noexcept { return 0.999f; } + +template<> +constexpr double dot_tolerance() noexcept { return 0.9999; } + +template +template +TMat33 TMat33::lookTo(const TVec3& direction, const TVec3& up) noexcept { + auto const z_axis = direction; + auto norm_up = up; + if (std::abs(dot(z_axis, norm_up)) > dot_tolerance< arithmetic_result_t >()) { + // Fix up vector if we're degenerate (looking straight up, basically) + norm_up = { norm_up.z, norm_up.x, norm_up.y }; + } + auto const x_axis = normalize(cross(z_axis, norm_up)); + auto const y_axis = cross(x_axis, z_axis); + return { x_axis, y_axis, -z_axis }; +} + +//------------------------------------------------------------------------------ +template +constexpr TQuaternion TMat33::packTangentFrame(const TMat33& m, size_t storageSize) noexcept { + TQuaternion q = TMat33{ m[0], cross(m[2], m[0]), m[2] }.toQuaternion(); + q = positive(normalize(q)); + + // Ensure w is never 0.0 + // Bias is 2^(nb_bits - 1) - 1 + const T bias = T(1.0) / T((1 << (storageSize * CHAR_BIT - 1)) - 1); + if (q.w < bias) { + q.w = bias; + + const T factor = (T)(std::sqrt(1.0 - (double)bias * (double)bias)); + q.xyz *= factor; + } + + // If there's a reflection ((n x t) . b <= 0), make sure w is negative + if (dot(cross(m[0], m[2]), m[1]) < T(0)) { + q = -q; + } + + return q; +} + + +} // namespace details + +/** + * Pre-scale a matrix m by the inverse of the largest scale factor to avoid large post-transform + * magnitudes in the shader. This is useful for normal transformations, to avoid large + * post-transform magnitudes in the shader, especially in the fragment shader, where we use + * medium precision. + */ +template +constexpr details::TMat33 prescaleForNormals(const details::TMat33& m) noexcept { + return m * details::TMat33( + 1.0 / std::sqrt(max(float3{length2(m[0]), length2(m[1]), length2(m[2])}))); +} + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat33 mat3; +typedef details::TMat33 mat3f; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat33& lhs, + filament::math::details::TMat33& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat33 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t02 = lhs[0][2]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + const T t12 = lhs[1][2]; + const T t20 = lhs[2][0]; + const T t21 = lhs[2][1]; + const T t22 = lhs[2][2]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[0][2] = rhs[0][2]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + lhs[1][2] = rhs[1][2]; + lhs[2][0] = rhs[2][0]; + lhs[2][1] = rhs[2][1]; + lhs[2][2] = rhs[2][2]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[0][2] = t02; + rhs[1][0] = t10; + rhs[1][1] = t11; + rhs[1][2] = t12; + rhs[2][0] = t20; + rhs[2][1] = t21; + rhs[2][2] = t22; +} +} + +#endif // TNT_MATH_MAT3_H diff --git a/package/ios/libs/filament/include/math/mat4.h b/package/ios/libs/filament/include/math/mat4.h new file mode 100644 index 00000000..57058539 --- /dev/null +++ b/package/ios/libs/filament/include/math/mat4.h @@ -0,0 +1,667 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_MAT4_H +#define TNT_MATH_MAT4_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- +namespace details { + +template +class TQuaternion; + +/** + * A 4x4 column-major matrix class. + * + * Conceptually a 4x4 matrix is a an array of 4 column double4: + * + * mat4 m = + * \f$ + * \left( + * \begin{array}{cccc} + * m[0] & m[1] & m[2] & m[3] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cccc} + * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\ + * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\ + * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\ + * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\ + * \end{array} + * \right) + * \f$ + * = + * \f$ + * \left( + * \begin{array}{cccc} + * m(0,0) & m(0,1) & m(0,2) & m(0,3) \\ + * m(1,0) & m(1,1) & m(1,2) & m(1,3) \\ + * m(2,0) & m(2,1) & m(2,2) & m(2,3) \\ + * m(3,0) & m(3,1) & m(3,2) & m(3,3) \\ + * \end{array} + * \right) + * \f$ + * + * m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4. + * + */ +template +class MATH_EMPTY_BASES TMat44 : + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecAddOperators, + public TMatProductOperators, + public TMatSquareFunctions, + public TMatTransform, + public TMatHelpers { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + typedef TVec4 col_type; + typedef TVec4 row_type; + + static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows) + static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns) + static constexpr size_t NUM_ROWS = COL_SIZE; + static constexpr size_t NUM_COLS = ROW_SIZE; + +private: + /* + * <-- N columns --> + * + * a[0][0] a[1][0] a[2][0] ... a[N][0] ^ + * a[0][1] a[1][1] a[2][1] ... a[N][1] | + * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows + * ... | + * a[0][M] a[1][M] a[2][M] ... a[N][M] v + * + * COL_SIZE = M + * ROW_SIZE = N + * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ] + */ + + col_type m_value[NUM_COLS]; + +public: + // array access + inline constexpr col_type const& operator[](size_t column) const noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + inline constexpr col_type& operator[](size_t column) noexcept { + assert(column < NUM_COLS); + return m_value[column]; + } + + /* + * constructors + */ + + // leaves object uninitialized. use with caution. + constexpr explicit TMat44(no_init) noexcept {} + + /** initialize to identity. + * + * \f$ + * \left( + * \begin{array}{cccc} + * 1 & 0 & 0 & 0 \\ + * 0 & 1 & 0 & 0 \\ + * 0 & 0 & 1 & 0 \\ + * 0 & 0 & 0 & 1 \\ + * \end{array} + * \right) + * \f$ + */ + constexpr TMat44() noexcept; + + /** initialize to Identity*scalar. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v & 0 & 0 & 0 \\ + * 0 & v & 0 & 0 \\ + * 0 & 0 & v & 0 \\ + * 0 & 0 & 0 & v \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat44(U v) noexcept; + + /** sets the diagonal to a vector. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v[0] & 0 & 0 & 0 \\ + * 0 & v[1] & 0 & 0 \\ + * 0 & 0 & v[2] & 0 \\ + * 0 & 0 & 0 & v[3] \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr explicit TMat44(const TVec4& v) noexcept; + + // construct from another matrix of the same size + template + constexpr explicit TMat44(const TMat44& rhs) noexcept; + + /** construct from 4 column vectors. + * + * \f$ + * \left( + * \begin{array}{cccc} + * v0 & v1 & v2 & v3 \\ + * \end{array} + * \right) + * \f$ + */ + template + constexpr TMat44(const TVec4& v0, const TVec4& v1, const TVec4& v2, + const TVec4& v3) noexcept; + + /** construct from 16 elements in column-major form. + * + * \f$ + * \left( + * \begin{array}{cccc} + * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\ + * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\ + * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\ + * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\ + * \end{array} + * \right) + * \f$ + */ + template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> + constexpr explicit TMat44(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept; + + + struct row_major_init { + template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> + constexpr explicit row_major_init(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept + : m(m00, m10, m20, m30, + m01, m11, m21, m31, + m02, m12, m22, m32, + m03, m13, m23, m33) {} + + private: + friend TMat44; + TMat44 m; + }; + + constexpr explicit TMat44(row_major_init c) noexcept : TMat44(std::move(c.m)) {} + + /** + * construct from a quaternion + */ + template + constexpr explicit TMat44(const TQuaternion& q) noexcept; + + /** + * construct from a 3x3 matrix + */ + template + constexpr explicit TMat44(const TMat33& matrix) noexcept; + + /** + * construct from a 3x3 matrix and 3d translation + */ + template + constexpr TMat44(const TMat33& matrix, const TVec3& translation) noexcept; + + /** + * construct from a 3x3 matrix and 4d last column. + */ + template + constexpr TMat44(const TMat33& matrix, const TVec4& column3) noexcept; + + static constexpr TMat44 ortho(T left, T right, T bottom, T top, T near, T far) noexcept; + + static constexpr TMat44 frustum(T left, T right, T bottom, T top, T near, T far) noexcept; + + enum class Fov { + HORIZONTAL, + VERTICAL + }; + static TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL) noexcept; + + template + static TMat44 lookAt(const TVec3& eye, const TVec3& center, const TVec3& up) noexcept; + + template + static TMat44 lookTo(const TVec3& direction, const TVec3& position, const TVec3& up) noexcept; + + template + static constexpr TVec3 project(const TMat44& projectionMatrix, TVec3 vertice) noexcept{ + TVec4 r = projectionMatrix * TVec4{ vertice, 1 }; + return TVec3{ r[0], r[1], r[2] } * (1 / r[3]); + } + + template + static constexpr TVec4 project(const TMat44& projectionMatrix, TVec4 vertice) noexcept{ + vertice = projectionMatrix * vertice; + return { TVec3{ vertice[0], vertice[1], vertice[2] } * (1 / vertice[3]), 1 }; + } + + /** + * Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix + */ + inline constexpr TMat33 upperLeft() const noexcept { + const TVec3 v0 = { m_value[0][0], m_value[0][1], m_value[0][2] }; + const TVec3 v1 = { m_value[1][0], m_value[1][1], m_value[1][2] }; + const TVec3 v2 = { m_value[2][0], m_value[2][1], m_value[2][2] }; + return TMat33(v0, v1, v2); + } + + template + static constexpr TMat44 translation(const TVec3& t) noexcept { + TMat44 r; + r[3] = TVec4{ t, 1 }; + return r; + } + + template + static constexpr TMat44 scaling(const TVec3& s) noexcept { + return TMat44{ TVec4{ s, 1 }}; + } + + template + static constexpr TMat44 scaling(A s) noexcept { + return TMat44{ TVec4{ s, s, s, 1 }}; + } +}; + +// ---------------------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------------------- + +// Since the matrix code could become pretty big quickly, we don't inline most +// operations. + +template +constexpr TMat44::TMat44() noexcept + : m_value{ + col_type(1, 0, 0, 0), + col_type(0, 1, 0, 0), + col_type(0, 0, 1, 0), + col_type(0, 0, 0, 1) } { +} + +template +template +constexpr TMat44::TMat44(U v) noexcept + : m_value{ + col_type(v, 0, 0, 0), + col_type(0, v, 0, 0), + col_type(0, 0, v, 0), + col_type(0, 0, 0, v) } { +} + +template +template +constexpr TMat44::TMat44(const TVec4& v) noexcept + : m_value{ + col_type(v[0], 0, 0, 0), + col_type(0, v[1], 0, 0), + col_type(0, 0, v[2], 0), + col_type(0, 0, 0, v[3]) } { +} + + +// construct from 16 scalars +template +template< + typename A, typename B, typename C, typename D, + typename E, typename F, typename G, typename H, + typename I, typename J, typename K, typename L, + typename M, typename N, typename O, typename P> +constexpr TMat44::TMat44(A m00, B m01, C m02, D m03, + E m10, F m11, G m12, H m13, + I m20, J m21, K m22, L m23, + M m30, N m31, O m32, P m33) noexcept + : m_value{ + col_type(m00, m01, m02, m03), + col_type(m10, m11, m12, m13), + col_type(m20, m21, m22, m23), + col_type(m30, m31, m32, m33) } { +} + +template +template +constexpr TMat44::TMat44(const TMat44& rhs) noexcept { + for (size_t col = 0; col < NUM_COLS; ++col) { + m_value[col] = col_type(rhs[col]); + } +} + +// Construct from 4 column vectors. +template +template +constexpr TMat44::TMat44(const TVec4& v0, const TVec4& v1, + const TVec4& v2, const TVec4& v3) noexcept + : m_value{ v0, v1, v2, v3 } { +} + +template +template +constexpr TMat44::TMat44(const TQuaternion& q) noexcept : m_value{} { + const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + const U s = n > 0 ? 2 / n : 0; + const U x = s * q.x; + const U y = s * q.y; + const U z = s * q.z; + const U xx = x * q.x; + const U xy = x * q.y; + const U xz = x * q.z; + const U xw = x * q.w; + const U yy = y * q.y; + const U yz = y * q.z; + const U yw = y * q.w; + const U zz = z * q.z; + const U zw = z * q.w; + m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw, 0); + m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw, 0); // NOLINT + m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy, 0); // NOLINT + m_value[3] = col_type(0, 0, 0, 1); // NOLINT +} + +template +template +constexpr TMat44::TMat44(const TMat33& m) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(0, 0, 0, 1) } // NOLINT +{ +} + +template +template +constexpr TMat44::TMat44(const TMat33& m, const TVec3& v) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(v[0], v[1], v[2], 1) } // NOLINT +{ +} + +template +template +constexpr TMat44::TMat44(const TMat33& m, const TVec4& v) noexcept + : m_value{ + col_type(m[0][0], m[0][1], m[0][2], 0), + col_type(m[1][0], m[1][1], m[1][2], 0), + col_type(m[2][0], m[2][1], m[2][2], 0), + col_type(v[0], v[1], v[2], v[3]) } // NOLINT +{ +} + + +// ---------------------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------------------- + +template +constexpr TMat44 TMat44::ortho(T left, T right, T bottom, T top, T near, T far) noexcept { + TMat44 m; + m[0][0] = 2 / (right - left); + m[1][1] = 2 / (top - bottom); + m[2][2] = -2 / (far - near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far - near); + return m; +} + +template +constexpr TMat44 TMat44::frustum(T left, T right, T bottom, T top, T near, T far) noexcept { + TMat44 m; + m[0][0] = (2 * near) / (right - left); + // 0 + // 0 + // 0 + + // 0 + m[1][1] = (2 * near) / (top - bottom); + // 0 + // 0 + + m[2][0] = (right + left) / (right - left); + m[2][1] = (top + bottom) / (top - bottom); + m[2][2] = -(far + near) / (far - near); + m[2][3] = -1; + + // 0 + // 0 + m[3][2] = -(2 * far * near) / (far - near); + m[3][3] = 0; + return m; +} + +template +TMat44 TMat44::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) noexcept { + T h, w; + + if (direction == TMat44::Fov::VERTICAL) { + h = std::tan(fov * F_PI / 360.0f) * near; + w = h * aspect; + } else { + w = std::tan(fov * F_PI / 360.0f) * near; + h = w / aspect; + } + return frustum(-w, w, -h, h, near, far); +} + +/* + * Returns a matrix representing the pose of a virtual camera looking towards -Z in its + * local Y-up coordinate system. "eye" is where the camera is located, "center" is the point it's + * looking at and "up" defines where the Y axis of the camera's local coordinate system is. + */ +template +template +TMat44 TMat44::lookAt(const TVec3& eye, const TVec3& center, + const TVec3& up) noexcept { + return lookTo(normalize(center - eye), eye, normalize(up)); +} + +template +template +TMat44 TMat44::lookTo(const TVec3& direction, const TVec3& position, + const TVec3& up) noexcept { + auto r = TMat33::lookTo(direction, up); + return TMat44{ + TVec4{ r[0], 0 }, + TVec4{ r[1], 0 }, + TVec4{ r[2], 0 }, + TVec4{ position, 1 } }; +} + +// ---------------------------------------------------------------------------------------- +// Arithmetic operators outside of class +// ---------------------------------------------------------------------------------------- + +// mat44 * vec3, result is vec3( mat44 * {vec3, 1} ) +template +constexpr typename TMat44::col_type MATH_PURE operator*(const TMat44& lhs, + const TVec3& rhs) noexcept { + return lhs * TVec4{ rhs, 1 }; +} + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TMat44 mat4; +typedef details::TMat44 mat4f; + +// mat4 * float4, with double precision intermediates +constexpr float4 highPrecisionMultiply(mat4f const& lhs, float4 const& rhs) noexcept { + double4 result{}; + result += lhs[0] * rhs[0]; + result += lhs[1] * rhs[1]; + result += lhs[2] * rhs[2]; + result += lhs[3] * rhs[3]; + return float4{ result }; +} + +// mat4 * mat4, with double precision intermediates +constexpr mat4f highPrecisionMultiply(mat4f const& lhs, mat4f const& rhs) noexcept { + return { + highPrecisionMultiply(lhs, rhs[0]), + highPrecisionMultiply(lhs, rhs[1]), + highPrecisionMultiply(lhs, rhs[2]), + highPrecisionMultiply(lhs, rhs[3]) + }; +} + +// mat4 * float4, with double precision intermediates +constexpr double4 highPrecisionMultiplyd(mat4f const& lhs, float4 const& rhs) noexcept { + double4 result{}; + result += lhs[0] * rhs[0]; + result += lhs[1] * rhs[1]; + result += lhs[2] * rhs[2]; + result += lhs[3] * rhs[3]; + return result; +} + +// mat4 * mat4, with double precision intermediates +constexpr mat4 highPrecisionMultiplyd(mat4f const& lhs, mat4f const& rhs) noexcept { + return { + highPrecisionMultiplyd(lhs, rhs[0]), + highPrecisionMultiplyd(lhs, rhs[1]), + highPrecisionMultiplyd(lhs, rhs[2]), + highPrecisionMultiplyd(lhs, rhs[3]) + }; +} + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +namespace std { +template +constexpr void swap(filament::math::details::TMat44& lhs, + filament::math::details::TMat44& rhs) noexcept { + // This generates much better code than the default implementation + // It's unclear why, I believe this is due to an optimization bug in the clang. + // + // filament::math::details::TMat44 t(lhs); + // lhs = rhs; + // rhs = t; + // + // clang always copy lhs on the stack, even if it's never using it (it's using the + // copy it has in registers). + + const T t00 = lhs[0][0]; + const T t01 = lhs[0][1]; + const T t02 = lhs[0][2]; + const T t03 = lhs[0][3]; + const T t10 = lhs[1][0]; + const T t11 = lhs[1][1]; + const T t12 = lhs[1][2]; + const T t13 = lhs[1][3]; + const T t20 = lhs[2][0]; + const T t21 = lhs[2][1]; + const T t22 = lhs[2][2]; + const T t23 = lhs[2][3]; + const T t30 = lhs[3][0]; + const T t31 = lhs[3][1]; + const T t32 = lhs[3][2]; + const T t33 = lhs[3][3]; + + lhs[0][0] = rhs[0][0]; + lhs[0][1] = rhs[0][1]; + lhs[0][2] = rhs[0][2]; + lhs[0][3] = rhs[0][3]; + lhs[1][0] = rhs[1][0]; + lhs[1][1] = rhs[1][1]; + lhs[1][2] = rhs[1][2]; + lhs[1][3] = rhs[1][3]; + lhs[2][0] = rhs[2][0]; + lhs[2][1] = rhs[2][1]; + lhs[2][2] = rhs[2][2]; + lhs[2][3] = rhs[2][3]; + lhs[3][0] = rhs[3][0]; + lhs[3][1] = rhs[3][1]; + lhs[3][2] = rhs[3][2]; + lhs[3][3] = rhs[3][3]; + + rhs[0][0] = t00; + rhs[0][1] = t01; + rhs[0][2] = t02; + rhs[0][3] = t03; + rhs[1][0] = t10; + rhs[1][1] = t11; + rhs[1][2] = t12; + rhs[1][3] = t13; + rhs[2][0] = t20; + rhs[2][1] = t21; + rhs[2][2] = t22; + rhs[2][3] = t23; + rhs[3][0] = t30; + rhs[3][1] = t31; + rhs[3][2] = t32; + rhs[3][3] = t33; +} +} + +#endif // TNT_MATH_MAT4_H diff --git a/package/ios/libs/filament/include/math/mathfwd.h b/package/ios/libs/filament/include/math/mathfwd.h new file mode 100644 index 00000000..b2d3ad84 --- /dev/null +++ b/package/ios/libs/filament/include/math/mathfwd.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef TNT_MATH_MATHFWD_H +#define TNT_MATH_MATHFWD_H + +#ifdef _MSC_VER + +// MSVC cannot compute the size of math types correctly when this file is included before the +// actual implementations. +// See github.com/google/filament/issues/2190. +#include +#include +#include +#include +#include +#include + +#else + +#include + +namespace filament::math { +namespace details { + +template class TVec2; +template class TVec3; +template class TVec4; + +template class TMat22; +template class TMat33; +template class TMat44; + +template class TQuaternion; + +} // namespace details + +using double2 = details::TVec2; +using float2 = details::TVec2; +using int2 = details::TVec2; +using uint2 = details::TVec2; +using short2 = details::TVec2; +using ushort2 = details::TVec2; +using byte2 = details::TVec2; +using ubyte2 = details::TVec2; +using bool2 = details::TVec2; + +using double3 = details::TVec3; +using float3 = details::TVec3; +using int3 = details::TVec3; +using uint3 = details::TVec3; +using short3 = details::TVec3; +using ushort3 = details::TVec3; +using byte3 = details::TVec3; +using ubyte3 = details::TVec3; +using bool3 = details::TVec3; + +using double4 = details::TVec4; +using float4 = details::TVec4; +using int4 = details::TVec4; +using uint4 = details::TVec4; +using short4 = details::TVec4; +using ushort4 = details::TVec4; +using byte4 = details::TVec4; +using ubyte4 = details::TVec4; +using bool4 = details::TVec4; + +using mat2 = details::TMat22; +using mat2f = details::TMat22; + +using mat3 = details::TMat33; +using mat3f = details::TMat33; + +using mat4 = details::TMat44; +using mat4f = details::TMat44; + +using quat = details::TQuaternion; +using quatf = details::TQuaternion; + +} // namespace filament::math + +#endif // _MSC_VER + +#endif // TNT_MATH_MATHFWD_H diff --git a/package/ios/libs/filament/include/math/norm.h b/package/ios/libs/filament/include/math/norm.h new file mode 100644 index 00000000..d4d99ba8 --- /dev/null +++ b/package/ios/libs/filament/include/math/norm.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_NORM_H +#define TNT_MATH_NORM_H + +#include +#include + +#include +#include + +namespace filament { +namespace math { + +inline uint16_t packUnorm16(float v) noexcept { + return static_cast(std::round(clamp(v, 0.0f, 1.0f) * 65535.0f)); +} + +inline ushort4 packUnorm16(float4 v) noexcept { + return ushort4{ packUnorm16(v.x), packUnorm16(v.y), packUnorm16(v.z), packUnorm16(v.w) }; +} + +inline int16_t packSnorm16(float v) noexcept { + return static_cast(std::round(clamp(v, -1.0f, 1.0f) * 32767.0f)); +} + +inline short2 packSnorm16(float2 v) noexcept { + return short2{ packSnorm16(v.x), packSnorm16(v.y) }; +} + +inline short4 packSnorm16(float4 v) noexcept { + return short4{ packSnorm16(v.x), packSnorm16(v.y), packSnorm16(v.z), packSnorm16(v.w) }; +} + +inline float unpackUnorm16(uint16_t v) noexcept { + return v / 65535.0f; +} + +inline float4 unpackUnorm16(ushort4 v) noexcept { + return float4{ unpackUnorm16(v.x), unpackUnorm16(v.y), unpackUnorm16(v.z), unpackUnorm16(v.w) }; +} + +inline float unpackSnorm16(int16_t v) noexcept { + return clamp(v / 32767.0f, -1.0f, 1.0f); +} + +inline float4 unpackSnorm16(short4 v) noexcept { + return float4{ unpackSnorm16(v.x), unpackSnorm16(v.y), unpackSnorm16(v.z), unpackSnorm16(v.w) }; +} + +inline uint8_t packUnorm8(float v) noexcept { + return static_cast(std::round(clamp(v, 0.0f, 1.0f) * 255.0)); +} + +inline ubyte4 packUnorm8(float4 v) noexcept { + return ubyte4{ packUnorm8(v.x), packUnorm8(v.y), packUnorm8(v.z), packUnorm8(v.w) }; +} + +inline int8_t packSnorm8(float v) noexcept { + return static_cast(std::round(clamp(v, -1.0f, 1.0f) * 127.0)); +} + +inline byte4 packSnorm8(float4 v) noexcept { + return byte4{ packSnorm8(v.x), packSnorm8(v.y), packSnorm8(v.z), packSnorm8(v.w) }; +} + +inline float unpackUnorm8(uint8_t v) noexcept { + return v / 255.0f; +} + +inline float4 unpackUnorm8(ubyte4 v) noexcept { + return float4{ unpackUnorm8(v.x), unpackUnorm8(v.y), unpackUnorm8(v.z), unpackUnorm8(v.w) }; +} + +inline float unpackSnorm8(int8_t v) noexcept { + return clamp(v / 127.0f, -1.0f, 1.0f); +} + +inline float4 unpackSnorm8(byte4 v) noexcept { + return float4{ unpackSnorm8(v.x), unpackSnorm8(v.y), unpackSnorm8(v.z), unpackSnorm8(v.w) }; +} + +} // namespace math +} // namespace filament + +#endif // TNT_MATH_NORM_H diff --git a/package/ios/libs/filament/include/math/quat.h b/package/ios/libs/filament/include/math/quat.h new file mode 100644 index 00000000..af9f7467 --- /dev/null +++ b/package/ios/libs/filament/include/math/quat.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 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. + */ + +#ifndef TNT_MATH_QUAT_H +#define TNT_MATH_QUAT_H + +#include +#include +#include +#include +#include + +#include +#include + +namespace filament::math { +namespace details { + +template +class MATH_EMPTY_BASES TQuaternion : + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TQuatProductOperators, + public TQuatFunctions { +public: + enum no_init { + NO_INIT + }; + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + + /* + * quaternion internals stored as: + * + * q = w + xi + yj + zk + * + * q[0] = x; + * q[1] = y; + * q[2] = z; + * q[3] = w; + * + */ + union { + struct { T x, y, z, w; }; + TVec4 xyzw; + TVec3 xyz; + TVec2 xy; + }; + + enum { SIZE = 4 }; + inline constexpr static size_type size() { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const { + // only possible in C++0x14 with constexpr + assert(i < SIZE); + return (&x)[i]; + } + + inline constexpr T& operator[](size_t i) { + assert(i < SIZE); + return (&x)[i]; + } + + // ----------------------------------------------------------------------- + // we want the compiler generated versions for these... + TQuaternion(const TQuaternion&) = default; + ~TQuaternion() = default; + TQuaternion& operator=(const TQuaternion&) = default; + + // constructors + + // Leaves object uninitialized. Use with caution. + explicit constexpr TQuaternion(no_init) {} + + // default constructor. sets all values to zero. + constexpr TQuaternion() : x(0), y(0), z(0), w(0) {} + + // Handles implicit conversion to a quat. Must not be explicit. + template> + constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {} // NOLINT(google-explicit-constructor) + + // initialize from 4 values to w + xi + yj + zk + template> + constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) {} + + // initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w + template> + constexpr TQuaternion(const TVec3& v, B w) : x(v.x), y(v.y), z(v.z), w(w) {} + + // initialize from a vec4 + template> + constexpr explicit TQuaternion(const TVec4& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} + + // initialize from a quaternion of a different type + template> + constexpr explicit TQuaternion(const TQuaternion& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} + + // conjugate operator + constexpr TQuaternion operator~() const { + return conj(*this); + } + + // constructs a quaternion from an axis and angle + template> + constexpr static TQuaternion MATH_PURE fromAxisAngle(const TVec3& axis, B angle) { + return TQuaternion(std::sin(angle * 0.5) * normalize(axis), std::cos(angle * 0.5)); + } + + // constructs a quaternion from orig to dest. + // it returns the shortest arc and `from` and `to` must be normalized. + template> + constexpr static TQuaternion MATH_PURE fromDirectedRotation(const TVec3& from, const TVec3& to) { + // see the implementation of glm/gtx/quaternion.hpp + T cosTheta = dot(from, to); + TVec3 rotationAxis; + + if (cosTheta >= T(1) - std::numeric_limits::epsilon()) { + // orig and dest point in the same direction + return TQuaternion(1, 0, 0, 0); + } + + if (cosTheta < T(-1) + std::numeric_limits::epsilon()) { + // special case when vectors in opposite directions : + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + // This implementation favors a rotation around the Up axis (Y), + // since it's often what you want to do. + rotationAxis = cross(TVec3(0, 0, 1), from); + + if (length2(rotationAxis) < std::numeric_limits::epsilon()) { + // bad luck, they were parallel, try again! + rotationAxis = cross(TVec3(1, 0, 0), from); + } + + rotationAxis = normalize(rotationAxis); + return fromAxisAngle(rotationAxis, F_PI); + } + + // implementation from Stan Melax's Game Programming Gems 1 article + rotationAxis = cross(from, to); + + const T s = std::sqrt((T(1) + cosTheta) * T(2)); + return TQuaternion(s * T(0.5), + rotationAxis.x / s, rotationAxis.y / s, rotationAxis.z / s); + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +typedef details::TQuaternion quat; +typedef details::TQuaternion quatf; +typedef details::TQuaternion quath; + +// note: don't put a space between "" and _{i,j,k}, this is deprecated + +constexpr inline quat operator ""_i(long double v) { + return { 0.0, double(v), 0.0, 0.0 }; +} + +constexpr inline quat operator ""_j(long double v) { + return { 0.0, 0.0, double(v), 0.0 }; +} + +constexpr inline quat operator ""_k(long double v) { + return { 0.0, 0.0, 0.0, double(v) }; +} + +constexpr inline quat operator ""_i(unsigned long long v) { + return { 0.0, double(v), 0.0, 0.0 }; +} + +constexpr inline quat operator ""_j(unsigned long long v) { + return { 0.0, 0.0, double(v), 0.0 }; +} + +constexpr inline quat operator ""_k(unsigned long long v) { + return { 0.0, 0.0, 0.0, double(v) }; +} + +} // namespace filament::math + +#endif // TNT_MATH_QUAT_H diff --git a/package/ios/libs/filament/include/math/scalar.h b/package/ios/libs/filament/include/math/scalar.h new file mode 100644 index 00000000..1de77d24 --- /dev/null +++ b/package/ios/libs/filament/include/math/scalar.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_MATH_SCALAR_H +#define TNT_MATH_SCALAR_H + +#include +#include + +namespace filament { +namespace math { + +constexpr const double F_E = 2.71828182845904523536028747135266250; +constexpr const double F_LOG2E = 1.44269504088896340735992468100189214; +constexpr const double F_LOG10E = 0.434294481903251827651128918916605082; +constexpr const double F_LN2 = 0.693147180559945309417232121458176568; +constexpr const double F_LN10 = 2.30258509299404568401799145468436421; +constexpr const double F_PI = 3.14159265358979323846264338327950288; +constexpr const double F_PI_2 = 1.57079632679489661923132169163975144; +constexpr const double F_PI_4 = 0.785398163397448309615660845819875721; +constexpr const double F_1_PI = 0.318309886183790671537767526745028724; +constexpr const double F_2_PI = 0.636619772367581343075535053490057448; +constexpr const double F_2_SQRTPI = 1.12837916709551257389615890312154517; +constexpr const double F_SQRT2 = 1.41421356237309504880168872420969808; +constexpr const double F_SQRT1_2 = 0.707106781186547524400844362104849039; +constexpr const double F_TAU = 2.0 * F_PI; + +namespace d { +constexpr const double E = F_E; +constexpr const double LOG2E = F_LOG2E; +constexpr const double LOG10E = F_LOG10E; +constexpr const double LN2 = F_LN2; +constexpr const double LN10 = F_LN10; +constexpr const double PI = F_PI; +constexpr const double PI_2 = F_PI_2; +constexpr const double PI_4 = F_PI_4; +constexpr const double ONE_OVER_PI = F_1_PI; +constexpr const double TWO_OVER_PI = F_2_PI; +constexpr const double TWO_OVER_SQRTPI = F_2_SQRTPI; +constexpr const double SQRT2 = F_SQRT2; +constexpr const double SQRT1_2 = F_SQRT1_2; +constexpr const double TAU = F_TAU; +constexpr const double DEG_TO_RAD = F_PI / 180.0; +constexpr const double RAD_TO_DEG = 180.0 / F_PI; +} // namespace d + +namespace f { +constexpr const float E = (float)d::E; +constexpr const float LOG2E = (float)d::LOG2E; +constexpr const float LOG10E = (float)d::LOG10E; +constexpr const float LN2 = (float)d::LN2; +constexpr const float LN10 = (float)d::LN10; +constexpr const float PI = (float)d::PI; +constexpr const float PI_2 = (float)d::PI_2; +constexpr const float PI_4 = (float)d::PI_4; +constexpr const float ONE_OVER_PI = (float)d::ONE_OVER_PI; +constexpr const float TWO_OVER_PI = (float)d::TWO_OVER_PI; +constexpr const float TWO_OVER_SQRTPI = (float)d::TWO_OVER_SQRTPI; +constexpr const float SQRT2 = (float)d::SQRT2; +constexpr const float SQRT1_2 = (float)d::SQRT1_2; +constexpr const float TAU = (float)d::TAU; +constexpr const float DEG_TO_RAD = (float)d::DEG_TO_RAD; +constexpr const float RAD_TO_DEG = (float)d::RAD_TO_DEG; +} // namespace f + +template +inline constexpr T MATH_PURE min(T a, T b) noexcept { + return a < b ? a : b; +} + +template +inline constexpr T MATH_PURE max(T a, T b) noexcept { + return a > b ? a : b; +} + +template +inline constexpr T MATH_PURE clamp(T v, T min, T max) noexcept { + assert(min <= max); + return T(math::min(max, math::max(min, v))); +} + +template +inline constexpr T MATH_PURE saturate(T v) noexcept { + return clamp(v, T(0), T(1)); +} + +template +inline constexpr T MATH_PURE mix(T x, T y, T a) noexcept { + return x * (T(1) - a) + y * a; +} + +template +inline constexpr T MATH_PURE lerp(T x, T y, T a) noexcept { + return mix(x, y, a); +} + +template +inline constexpr T MATH_PURE smoothstep(T e0, T e1, T x) noexcept { + T t = clamp((x - e0) / (e1 - e0), T(0), T(1)); + return t * t * (T(3) - T(2) * t); +} + +template +inline constexpr T sign(T x) noexcept { + return x < T(0) ? T(-1) : T(1); +} + +} // namespace math +} // namespace filament + +#endif // TNT_MATH_SCALAR_H diff --git a/package/ios/libs/filament/include/math/vec2.h b/package/ios/libs/filament/include/math/vec2.h new file mode 100644 index 00000000..16c11858 --- /dev/null +++ b/package/ios/libs/filament/include/math/vec2.h @@ -0,0 +1,114 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC2_H +#define TNT_MATH_VEC2_H + +#include +#include + +#include + +#include +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec2 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 2; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + struct { T x, y; }; + struct { T s, t; }; + struct { T r, g; }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec2() MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec4. must not be explicit. + template> + constexpr TVec2(A v) noexcept : v{ T(v), T(v) } {} + + template> + constexpr TVec2(A x, B y) noexcept : v{ T(x), T(y) } {} + + template> + constexpr TVec2(const TVec2& v) noexcept : v{ T(v[0]), T(v[1]) } {} + + // cross product works only on vectors of size 2 or 3 + template + friend inline constexpr + arithmetic_result_t cross(const TVec2& u, const TVec2& v) noexcept { + return u[0] * v[1] - u[1] * v[0]; + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec2 = details::TVec2; + +using double2 = vec2; +using float2 = vec2; +using half2 = vec2; +using int2 = vec2; +using uint2 = vec2; +using short2 = vec2; +using ushort2 = vec2; +using byte2 = vec2; +using ubyte2 = vec2; +using bool2 = vec2; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC2_H diff --git a/package/ios/libs/filament/include/math/vec3.h b/package/ios/libs/filament/include/math/vec3.h new file mode 100644 index 00000000..fc856ede --- /dev/null +++ b/package/ios/libs/filament/include/math/vec3.h @@ -0,0 +1,133 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC3_H +#define TNT_MATH_VEC3_H + +#include +#include + +#include +#include + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec3 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 3; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + TVec2 xy; + TVec2 st; + TVec2 rg; + struct { + union { + T x; + T s; + T r; + }; + union { + struct { T y, z; }; + struct { T t, p; }; + struct { T g, b; }; + TVec2 yz; + TVec2 tp; + TVec2 gb; + }; + }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec3() noexcept MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec3. must not be explicit. + template> + constexpr TVec3(A v) noexcept : v{ T(v), T(v), T(v) } {} + + template> + constexpr TVec3(A x, B y, C z) noexcept : v{ T(x), T(y), T(z) } {} + + template> + constexpr TVec3(const TVec2& v, B z) noexcept : v{ T(v[0]), T(v[1]), T(z) } {} + + template> + constexpr TVec3(const TVec3& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]) } {} + + // cross product works only on vectors of size 3 + template + friend inline constexpr + TVec3> cross(const TVec3& u, const TVec3& v) noexcept { + return { + u[1] * v[2] - u[2] * v[1], + u[2] * v[0] - u[0] * v[2], + u[0] * v[1] - u[1] * v[0] }; + } +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec3 = details::TVec3; + +using double3 = vec3; +using float3 = vec3; +using half3 = vec3; +using int3 = vec3; +using uint3 = vec3; +using short3 = vec3; +using ushort3 = vec3; +using byte3 = vec3; +using ubyte3 = vec3; +using bool3 = vec3; + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC3_H diff --git a/package/ios/libs/filament/include/math/vec4.h b/package/ios/libs/filament/include/math/vec4.h new file mode 100644 index 00000000..77877d5d --- /dev/null +++ b/package/ios/libs/filament/include/math/vec4.h @@ -0,0 +1,133 @@ +/* + * Copyright 2013 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. + */ + +#ifndef TNT_MATH_VEC4_H +#define TNT_MATH_VEC4_H + +#include +#include + +#include +#include + + +namespace filament { +namespace math { +// ------------------------------------------------------------------------------------- + +namespace details { + +template +class MATH_EMPTY_BASES TVec4 : + public TVecProductOperators, + public TVecAddOperators, + public TVecUnaryOperators, + public TVecComparisonOperators, + public TVecFunctions { +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef size_t size_type; + static constexpr size_t SIZE = 4; + + union { + T v[SIZE] MATH_CONSTEXPR_INIT; + TVec2 xy, st, rg; + TVec3 xyz, stp, rgb; + struct { + union { T x, s, r; }; + union { + TVec2 yz, tp, gb; + TVec3 yzw, tpq, gba; + struct { + union { T y, t, g; }; + union { + TVec2 zw, pq, ba; + struct { T z, w; }; + struct { T p, q; }; + struct { T b, a; }; + }; + }; + }; + }; + }; + + inline constexpr size_type size() const { return SIZE; } + + // array access + inline constexpr T const& operator[](size_t i) const noexcept { + assert(i < SIZE); + return v[i]; + } + + inline constexpr T& operator[](size_t i) noexcept { + assert(i < SIZE); + return v[i]; + } + + // constructors + + // default constructor + MATH_DEFAULT_CTOR_CONSTEXPR TVec4() noexcept MATH_DEFAULT_CTOR + + // handles implicit conversion to a tvec4. must not be explicit. + template> + constexpr TVec4(A v) noexcept : v{ T(v), T(v), T(v), T(v) } {} + + template> + constexpr TVec4(A x, B y, C z, D w) noexcept : v{ T(x), T(y), T(z), T(w) } {} + + template> + constexpr TVec4(const TVec2& v, B z, C w) noexcept : v{ T(v[0]), T(v[1]), T(z), T(w) } {} + + template> + constexpr TVec4(const TVec2& v, const TVec2& w) noexcept : v{ + T(v[0]), T(v[1]), T(w[0]), T(w[1]) } {} + + template> + constexpr TVec4(const TVec3& v, B w) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(w) } {} + + template> + constexpr TVec4(const TVec4& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(v[3]) } {} +}; + +} // namespace details + +// ---------------------------------------------------------------------------------------- + +template> +using vec4 = details::TVec4; + +using double4 = vec4; +using float4 = vec4; +using half4 = vec4; +using int4 = vec4; +using uint4 = vec4; +using short4 = vec4; +using ushort4 = vec4; +using byte4 = vec4; +using ubyte4 = vec4; +using bool4 = vec4; + + +// ---------------------------------------------------------------------------------------- +} // namespace math +} // namespace filament + +#endif // TNT_MATH_VEC4_H diff --git a/package/ios/libs/filament/include/mathio/ostream.h b/package/ios/libs/filament/include/mathio/ostream.h new file mode 100644 index 00000000..5628e7c8 --- /dev/null +++ b/package/ios/libs/filament/include/mathio/ostream.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if __has_attribute(visibility) +# define MATHIO_PUBLIC __attribute__((visibility("default"))) +#else +# define MATHIO_PUBLIC +#endif + +namespace filament::math::details { + +template class TQuaternion; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec2& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec3& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TVec4& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat22& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat33& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TMat44& v) noexcept; + +template +MATHIO_PUBLIC +std::ostream& operator<<(std::ostream& out, const TQuaternion& v) noexcept; + +} // namespace filament::math::details diff --git a/package/ios/libs/filament/include/mikktspace/mikktspace.h b/package/ios/libs/filament/include/mikktspace/mikktspace.h new file mode 100644 index 00000000..52c44a71 --- /dev/null +++ b/package/ios/libs/filament/include/mikktspace/mikktspace.h @@ -0,0 +1,145 @@ +/** \file mikktspace/mikktspace.h + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef __MIKKTSPACE_H__ +#define __MIKKTSPACE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Author: Morten S. Mikkelsen + * Version: 1.0 + * + * The files mikktspace.h and mikktspace.c are designed to be + * stand-alone files and it is important that they are kept this way. + * Not having dependencies on structures/classes/libraries specific + * to the program, in which they are used, allows them to be copied + * and used as is into any tool, program or plugin. + * The code is designed to consistently generate the same + * tangent spaces, for a given mesh, in any tool in which it is used. + * This is done by performing an internal welding step and subsequently an order-independent evaluation + * of tangent space for meshes consisting of triangles and quads. + * This means faces can be received in any order and the same is true for + * the order of vertices of each face. The generated result will not be affected + * by such reordering. Additionally, whether degenerate (vertices or texture coordinates) + * primitives are present or not will not affect the generated results either. + * Once tangent space calculation is done the vertices of degenerate primitives will simply + * inherit tangent space from neighboring non degenerate primitives. + * The analysis behind this implementation can be found in my master's thesis + * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/package/ios/libs/filament/include/tsl/robin_growth_policy.h b/package/ios/libs/filament/include/tsl/robin_growth_policy.h new file mode 100644 index 00000000..daf6bf56 --- /dev/null +++ b/package/ios/libs/filament/include/tsl/robin_growth_policy.h @@ -0,0 +1,290 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_GROWTH_POLICY_H +#define TSL_ROBIN_GROWTH_POLICY_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __EXCEPTIONS +# define THROW(_e, _m) throw _e(_m) +#else +# include +# ifndef NDEBUG +# define THROW(_e, _m) do { fprintf(stderr, _m); std::terminate(); } while(0) +# else +# define THROW(_e, _m) std::terminate() +# endif +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_builtin(__builtin_expect) +# define TSL_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +#else +# define TSL_LIKELY( exp ) (exp) +#endif + +namespace tsl { +namespace rh { + +/** + * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows + * the table to use a mask operation instead of a modulo operation to map a hash to a bucket. + * + * GrowthFactor must be a power of two >= 2. + */ +template +class power_of_two_growth_policy { +public: + /** + * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter. + * This number is a minimum, the policy may update this value with a higher value if needed (but not lower). + */ + power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) { + if(min_bucket_count_in_out > max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + static_assert(MIN_BUCKETS_SIZE > 0, "MIN_BUCKETS_SIZE must be > 0."); + const std::size_t min_bucket_count = MIN_BUCKETS_SIZE; + + min_bucket_count_in_out = std::max(min_bucket_count, min_bucket_count_in_out); + min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out); + m_mask = min_bucket_count_in_out - 1; + } + + /** + * Return the bucket [0, bucket_count()) to which the hash belongs. + */ + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash & m_mask; + } + + /** + * Return the bucket count to use when the bucket array grows on rehash. + */ + std::size_t next_bucket_count() const { + if((m_mask + 1) > max_bucket_count() / GrowthFactor) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + return (m_mask + 1) * GrowthFactor; + } + + /** + * Return the maximum number of buckets supported by the policy. + */ + std::size_t max_bucket_count() const { + // Largest power of two. + return (std::numeric_limits::max() / 2) + 1; + } + +private: + static std::size_t round_up_to_power_of_two(std::size_t value) { + if(is_power_of_two(value)) { + return value; + } + + if(value == 0) { + return 1; + } + + --value; + for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { + value |= value >> i; + } + + return value + 1; + } + + static constexpr bool is_power_of_two(std::size_t value) { + return value != 0 && (value & (value - 1)) == 0; + } + +protected: + static const std::size_t MIN_BUCKETS_SIZE = 2; + static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2."); + + std::size_t m_mask; +}; + + +/** + * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash + * to a bucket. Slower but it can be usefull if you want a slower growth. + */ +template> +class mod_growth_policy { +public: + mod_growth_policy(std::size_t& min_bucket_count_in_out) { + if(min_bucket_count_in_out > max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + static_assert(MIN_BUCKETS_SIZE > 0, "MIN_BUCKETS_SIZE must be > 0."); + const std::size_t min_bucket_count = MIN_BUCKETS_SIZE; + + min_bucket_count_in_out = std::max(min_bucket_count, min_bucket_count_in_out); + m_bucket_count = min_bucket_count_in_out; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash % m_bucket_count; + } + + std::size_t next_bucket_count() const { + if(m_bucket_count == max_bucket_count()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + const double next_bucket_count = std::ceil(double(m_bucket_count) * REHASH_SIZE_MULTIPLICATION_FACTOR); + if(!std::isnormal(next_bucket_count)) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + if(next_bucket_count > double(max_bucket_count())) { + return max_bucket_count(); + } + else { + return std::size_t(next_bucket_count); + } + } + + std::size_t max_bucket_count() const { + return MAX_BUCKET_COUNT; + } + +private: + static const std::size_t MIN_BUCKETS_SIZE = 2; + static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den; + static const std::size_t MAX_BUCKET_COUNT = + std::size_t(double( + std::numeric_limits::max() / REHASH_SIZE_MULTIPLICATION_FACTOR + )); + + static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1."); + + std::size_t m_bucket_count; +}; + + + +namespace detail { + +static constexpr const std::array PRIMES = {{ + 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul, 1543ul, 2053ul, + 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, + 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, + 1610612741ul, 3221225473ul, 4294967291ul +}}; + +template +static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; } + +// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the +// compiler can optimize the modulo code better with a constant known at the compilation. +static constexpr const std::array MOD_PRIME = {{ + &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, + &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, + &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, + &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38> +}}; + +} + +/** + * Grow the hash table by using prime numbers as bucket count. Slower than tsl::rh::power_of_two_growth_policy in + * general but will probably distribute the values around better in the buckets with a poor hash function. + * + * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers. + * + * With a switch the code would look like: + * \code + * switch(iprime) { // iprime is the current prime of the hash table + * case 0: hash % 5ul; + * break; + * case 1: hash % 17ul; + * break; + * case 2: hash % 29ul; + * break; + * ... + * } + * \endcode + * + * Due to the constant variable in the modulo the compiler is able to optimize the operation + * by a series of multiplications, substractions and shifts. + * + * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement. + */ +class prime_growth_policy { +public: + prime_growth_policy(std::size_t& min_bucket_count_in_out) { + auto it_prime = std::lower_bound(detail::PRIMES.begin(), + detail::PRIMES.end(), min_bucket_count_in_out); + if(it_prime == detail::PRIMES.end()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + m_iprime = static_cast(std::distance(detail::PRIMES.begin(), it_prime)); + min_bucket_count_in_out = *it_prime; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return detail::MOD_PRIME[m_iprime](hash); + } + + std::size_t next_bucket_count() const { + if(m_iprime + 1 >= detail::PRIMES.size()) { + THROW(std::length_error, "The hash table exceeds its maxmimum size."); + } + + return detail::PRIMES[m_iprime + 1]; + } + + std::size_t max_bucket_count() const { + return detail::PRIMES.back(); + } + +private: + unsigned int m_iprime; + + static_assert(std::numeric_limits::max() >= detail::PRIMES.size(), + "The type of m_iprime is not big enough."); +}; + +} +} + +#endif diff --git a/package/ios/libs/filament/include/tsl/robin_hash.h b/package/ios/libs/filament/include/tsl/robin_hash.h new file mode 100644 index 00000000..0f94a07a --- /dev/null +++ b/package/ios/libs/filament/include/tsl/robin_hash.h @@ -0,0 +1,1252 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_HASH_H +#define TSL_ROBIN_HASH_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "robin_growth_policy.h" + + + +#ifndef tsl_assert + #ifdef TSL_DEBUG + #define tsl_assert(expr) assert(expr) + #else + #define tsl_assert(expr) (static_cast(0)) + #endif +#endif + + + +namespace tsl { + +namespace detail_robin_hash { + +template +struct make_void { + using type = void; +}; + +template +struct has_is_transparent: std::false_type { +}; + +template +struct has_is_transparent::type>: std::true_type { +}; + +template +struct is_power_of_two_policy: std::false_type { +}; + +template +struct is_power_of_two_policy>: std::true_type { +}; + + + +using truncated_hash_type = std::uint_least32_t; + +/** + * Helper class that store a truncated hash if StoreHash is true and nothing otherwise. + */ +template +class bucket_entry_hash { +public: + bool bucket_hash_equal(std::size_t /*hash*/) const noexcept { + return true; + } + + truncated_hash_type truncated_hash() const noexcept { + return 0; + } + +protected: + void set_hash(truncated_hash_type /*hash*/) noexcept { + } +}; + +template<> +class bucket_entry_hash { +public: + bool bucket_hash_equal(std::size_t hash) const noexcept { + return m_hash == truncated_hash_type(hash); + } + + truncated_hash_type truncated_hash() const noexcept { + return m_hash; + } + +protected: + void set_hash(truncated_hash_type hash) noexcept { + m_hash = truncated_hash_type(hash); + } + +private: + truncated_hash_type m_hash; +}; + + +/** + * Each bucket entry has: + * - A value of type `ValueType`. + * - An integer to store how far the value of the bucket, if any, is from its ideal bucket + * (ex: if the current bucket 5 has the value 'foo' and `hash('foo') % nb_buckets` == 3, + * `dist_from_ideal_bucket()` will return 2 as the current value of the bucket is two + * buckets away from its ideal bucket) + * If there is no value in the bucket (i.e. `empty()` is true) `dist_from_ideal_bucket()` will be < 0. + * - A marker which tells us if the bucket is the last bucket of the bucket array (useful for the + * iterator of the hash table). + * - If `StoreHash` is true, 32 bits of the hash of the value, if any, are also stored in the bucket. + * If the size of the hash is more than 32 bits, it is truncated. We don't store the full hash + * as storing the hash is a potential opportunity to use the unused space due to the alignement + * of the bucket_entry structure. We can thus potentially store the hash without any extra space + * (which would not be possible with 64 bits of the hash). + */ +template +class bucket_entry: public bucket_entry_hash { + using bucket_hash = bucket_entry_hash; + +public: + using value_type = ValueType; + using distance_type = std::int_least16_t; + + + bucket_entry() noexcept: bucket_hash(), m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(false) + { + tsl_assert(empty()); + } + + bucket_entry(const bucket_entry& other) noexcept(std::is_nothrow_copy_constructible::value): + bucket_hash(other), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) + { + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(other.value()); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + } + + /** + * Never really used, but still necessary as we must call resize on an empty `std::vector`. + * and we need to support move-only types. See robin_hash constructor for details. + */ + bucket_entry(bucket_entry&& other) noexcept(std::is_nothrow_move_constructible::value): + bucket_hash(std::move(other)), + m_dist_from_ideal_bucket(EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET), + m_last_bucket(other.m_last_bucket) + { + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(std::move(other.value())); + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + } + } + + bucket_entry& operator=(const bucket_entry& other) + noexcept(std::is_nothrow_copy_constructible::value) + { + if(this != &other) { + clear(); + + bucket_hash::operator=(other); + if(!other.empty()) { + ::new (static_cast(std::addressof(m_value))) value_type(other.value()); + } + + m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; + m_last_bucket = other.m_last_bucket; + } + + return *this; + } + + bucket_entry& operator=(bucket_entry&& ) = delete; + + ~bucket_entry() noexcept { + clear(); + } + + void clear() noexcept { + if(!empty()) { + destroy_value(); + m_dist_from_ideal_bucket = EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + } + + bool empty() const noexcept { + return m_dist_from_ideal_bucket == EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET; + } + + value_type& value() noexcept { + tsl_assert(!empty()); + return *reinterpret_cast(std::addressof(m_value)); + } + + const value_type& value() const noexcept { + tsl_assert(!empty()); + return *reinterpret_cast(std::addressof(m_value)); + } + + distance_type dist_from_ideal_bucket() const noexcept { + return m_dist_from_ideal_bucket; + } + + bool last_bucket() const noexcept { + return m_last_bucket; + } + + void set_as_last_bucket() noexcept { + m_last_bucket = true; + } + + template + void set_value_of_empty_bucket(distance_type dist_from_ideal_bucket, + truncated_hash_type hash, Args&&... value_type_args) + { + tsl_assert(dist_from_ideal_bucket >= 0); + tsl_assert(empty()); + + ::new (static_cast(std::addressof(m_value))) value_type(std::forward(value_type_args)...); + this->set_hash(hash); + m_dist_from_ideal_bucket = dist_from_ideal_bucket; + + tsl_assert(!empty()); + } + + void swap_with_value_in_bucket(distance_type& dist_from_ideal_bucket, + truncated_hash_type& hash, value_type& value) + { + tsl_assert(!empty()); + + using std::swap; + swap(value, this->value()); + swap(dist_from_ideal_bucket, m_dist_from_ideal_bucket); + + // Avoid warning of unused variable if StoreHash is false + (void) hash; + if(StoreHash) { + const truncated_hash_type tmp_hash = this->truncated_hash(); + this->set_hash(hash); + hash = tmp_hash; + } + } + + static truncated_hash_type truncate_hash(std::size_t hash) noexcept { + return truncated_hash_type(hash); + } + +private: + void destroy_value() noexcept { + tsl_assert(!empty()); + value().~value_type(); + } + +private: + using storage = typename std::aligned_storage::type; + + static const distance_type EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET = -1; + + distance_type m_dist_from_ideal_bucket; + bool m_last_bucket; + storage m_value; +}; + + + +/** + * Internal common class used by `robin_map` and `robin_set`. + * + * ValueType is what will be stored by `robin_hash` (usually `std::pair` for map and `Key` for set). + * + * `KeySelect` should be a `FunctionObject` which takes a `ValueType` in parameter and returns a + * reference to the key. + * + * `ValueSelect` should be a `FunctionObject` which takes a `ValueType` in parameter and returns a + * reference to the value. `ValueSelect` should be void if there is no value (in a set for example). + * + * The strong exception guarantee only holds if the expression + * `std::is_nothrow_swappable::value && std::is_nothrow_move_constructible::value` is true. + * + * Behaviour is undefined if the destructor of `ValueType` throws. + */ +template +class robin_hash: private Hash, private KeyEqual, private GrowthPolicy { +private: + template + using has_mapped_type = typename std::integral_constant::value>; + + +public: + template + class robin_iterator; + + using key_type = typename KeySelect::key_type; + using value_type = ValueType; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = robin_iterator; + using const_iterator = robin_iterator; + + +private: + /** + * Either store the hash because we are asked by the `StoreHash` template parameter + * or store the hash because it doesn't cost us anything in size and can be used to speed up rehash. + */ + static constexpr bool STORE_HASH = StoreHash || + ( + (sizeof(tsl::detail_robin_hash::bucket_entry) == + sizeof(tsl::detail_robin_hash::bucket_entry)) + && + (sizeof(std::size_t) == sizeof(truncated_hash_type) || + is_power_of_two_policy::value) + && + // Don't store the hash for primitive types with default hash. + (!std::is_arithmetic::value || + !std::is_same>::value) + ); + + /** + * Only use the stored hash on lookup if we are explictly asked. We are not sure how slow + * the KeyEqual operation is. An extra comparison may slow things down with a fast KeyEqual. + */ + static constexpr bool USE_STORED_HASH_ON_LOOKUP = StoreHash; + + /** + * We can only use the hash on rehash if the size of the hash type is the same as the stored one or + * if we use a power of two modulo. In the case of the power of two modulo, we just mask + * the least significant bytes, we just have to check that the truncated_hash_type didn't truncated + * more bytes. + */ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#endif + + static bool USE_STORED_HASH_ON_REHASH(size_type bucket_count) { + (void) bucket_count; + if(STORE_HASH && sizeof(std::size_t) == sizeof(truncated_hash_type)) { + return true; + } + else if(STORE_HASH && is_power_of_two_policy::value) { + tsl_assert(bucket_count > 0); + return (bucket_count - 1) <= std::numeric_limits::max(); + } + else { + return false; + } + } + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + using bucket_entry = tsl::detail_robin_hash::bucket_entry; + using distance_type = typename bucket_entry::distance_type; + + using buckets_allocator = typename std::allocator_traits::template rebind_alloc; + using buckets_container_type = std::vector; + + +public: + /** + * The 'operator*()' and 'operator->()' methods return a const reference and const pointer respectively to the + * stored value type. + * + * In case of a map, to get a mutable reference to the value associated to a key (the '.second' in the + * stored pair), you have to call 'value()'. + * + * The main reason for this is that if we returned a `std::pair&` instead + * of a `const std::pair&`, the user may modify the key which will put the map in a undefined state. + */ + template + class robin_iterator { + friend class robin_hash; + + private: + using iterator_bucket = typename std::conditional::type; + + + robin_iterator(iterator_bucket it) noexcept: m_iterator(it) { + } + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const typename robin_hash::value_type; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + + + robin_iterator() noexcept { + } + + robin_iterator(const robin_iterator& other) noexcept: m_iterator(other.m_iterator) { + } + + const typename robin_hash::key_type& key() const { + return KeySelect()(m_iterator->value()); + } + + template::value && IsConst>::type* = nullptr> + const typename U::value_type& value() const { + return U()(m_iterator->value()); + } + + template::value && !IsConst>::type* = nullptr> + typename U::value_type& value() { + return U()(m_iterator->value()); + } + + reference operator*() const { + return m_iterator->value(); + } + + pointer operator->() const { + return std::addressof(m_iterator->value()); + } + + robin_iterator& operator++() { + while(true) { + if(m_iterator->last_bucket()) { + ++m_iterator; + return *this; + } + + ++m_iterator; + if(!m_iterator->empty()) { + return *this; + } + } + } + + robin_iterator operator++(int) { + robin_iterator tmp(*this); + ++*this; + + return tmp; + } + + friend bool operator==(const robin_iterator& lhs, const robin_iterator& rhs) { + return lhs.m_iterator == rhs.m_iterator; + } + + friend bool operator!=(const robin_iterator& lhs, const robin_iterator& rhs) { + return !(lhs == rhs); + } + + private: + iterator_bucket m_iterator; + }; + + +public: + robin_hash(size_type bucket_count, + const Hash& hash, + const KeyEqual& equal, + const Allocator& alloc, + float max_load_factor): Hash(hash), KeyEqual(equal), + // We need a non-zero bucket_count + GrowthPolicy(bucket_count == 0?++bucket_count:bucket_count), + m_buckets(alloc), + m_bucket_count(bucket_count), + m_nb_elements(0), + m_grow_on_next_insert(false) + { + if(bucket_count > max_bucket_count()) { + THROW(std::length_error, "The map exceeds its maxmimum size."); + } + + /* + * We can't use the `vector(size_type count, const Allocator& alloc)` constructor + * as it's only available in C++14 and we need to support C++11. We thus must resize after using + * the `vector(const Allocator& alloc)` constructor. + * + * We can't use `vector(size_type count, const T& value, const Allocator& alloc)` as it requires the + * value T to be copyable. + */ + m_buckets.resize(m_bucket_count); + + tsl_assert(!m_buckets.empty()); + m_buckets.back().set_as_last_bucket(); + + + this->max_load_factor(max_load_factor); + } + + robin_hash(const robin_hash& other) = default; + + robin_hash(robin_hash&& other) noexcept(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value) + : Hash(std::move(static_cast(other))), + KeyEqual(std::move(static_cast(other))), + GrowthPolicy(std::move(static_cast(other))), + m_buckets(std::move(other.m_buckets)), + m_bucket_count(other.m_bucket_count), + m_nb_elements(other.m_nb_elements), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + other.clear(); + } + + robin_hash& operator=(const robin_hash& other) = default; + + robin_hash& operator=(robin_hash&& other) { + other.swap(*this); + other.clear(); + + return *this; + } + + allocator_type get_allocator() const { + return m_buckets.get_allocator(); + } + + + /* + * Iterators + */ + iterator begin() noexcept { + auto begin = m_buckets.begin(); + while(begin != m_buckets.end() && begin->empty()) { + ++begin; + } + + return iterator(begin); + } + + const_iterator begin() const noexcept { + return cbegin(); + } + + const_iterator cbegin() const noexcept { + auto begin = m_buckets.cbegin(); + while(begin != m_buckets.cend() && begin->empty()) { + ++begin; + } + + return const_iterator(begin); + } + + iterator end() noexcept { + return iterator(m_buckets.end()); + } + + const_iterator end() const noexcept { + return cend(); + } + + const_iterator cend() const noexcept { + return const_iterator(m_buckets.cend()); + } + + + /* + * Capacity + */ + bool empty() const noexcept { + return m_nb_elements == 0; + } + + size_type size() const noexcept { + return m_nb_elements; + } + + size_type max_size() const noexcept { + return m_buckets.max_size(); + } + + /* + * Modifiers + */ + void clear() noexcept { + for(auto& bucket: m_buckets) { + bucket.clear(); + } + + m_nb_elements = 0; + m_grow_on_next_insert = false; + } + + + + template + std::pair insert(P&& value) { + return insert_impl(KeySelect()(value), std::forward

(value)); + } + + template + iterator insert(const_iterator hint, P&& value) { + if(hint != cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) { + return mutable_iterator(hint); + } + + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + if(std::is_base_of::iterator_category>::value) + { + const auto nb_elements_insert = std::distance(first, last); + const size_type nb_free_buckets = m_load_threshold - size(); + tsl_assert(m_load_threshold >= size()); + + if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) { + reserve(size() + size_type(nb_elements_insert)); + } + } + + for(; first != last; ++first) { + insert(*first); + } + } + + + + template + std::pair insert_or_assign(K&& key, M&& obj) { + auto it = try_emplace(std::forward(key), std::forward(obj)); + if(!it.second) { + it.first.value() = std::forward(obj); + } + + return it; + } + + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + auto it = mutable_iterator(hint); + it.value() = std::forward(obj); + + return it; + } + + return insert_or_assign(std::forward(key), std::forward(obj)).first; + } + + + template + std::pair emplace(Args&&... args) { + return insert(value_type(std::forward(args)...)); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return insert(hint, value_type(std::forward(args)...)); + } + + + + template + std::pair try_emplace(K&& key, Args&&... args) { + return insert_impl(key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); + } + + template + iterator try_emplace(const_iterator hint, K&& key, Args&&... args) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + return mutable_iterator(hint); + } + + return try_emplace(std::forward(key), std::forward(args)...).first; + } + + /** + * Here to avoid `template size_type erase(const K& key)` being used when + * we use a iterator instead of a const_iterator. + */ + iterator erase(iterator pos) { + erase_from_bucket(pos); + + /** + * Erase bucket used a backward shift after clearing the bucket. + * Check if there is a new value in the bucket, if not get the next non-empty. + */ + if(pos.m_iterator->empty()) { + ++pos; + } + + return pos; + } + + iterator erase(const_iterator pos) { + return erase(mutable_iterator(pos)); + } + + iterator erase(const_iterator first, const_iterator last) { + if(first == last) { + return mutable_iterator(first); + } + + auto first_mutable = mutable_iterator(first); + auto last_mutable = mutable_iterator(last); + for(auto it = first_mutable.m_iterator; it != last_mutable.m_iterator; ++it) { + if(!it->empty()) { + it->clear(); + m_nb_elements--; + } + } + + if(last_mutable == end()) { + return end(); + } + + + /* + * Backward shift on the values which come after the deleted values. + * We try to move the values closer to their ideal bucket. + */ + std::size_t icloser_bucket = std::size_t(std::distance(m_buckets.begin(), first_mutable.m_iterator)); + std::size_t ito_move_closer_value = std::size_t(std::distance(m_buckets.begin(), last_mutable.m_iterator)); + tsl_assert(ito_move_closer_value > icloser_bucket); + + const std::size_t ireturn_bucket = ito_move_closer_value - + std::min(ito_move_closer_value - icloser_bucket, + std::size_t(m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + while(ito_move_closer_value < m_buckets.size() && m_buckets[ito_move_closer_value].dist_from_ideal_bucket() > 0) { + icloser_bucket = ito_move_closer_value - + std::min(ito_move_closer_value - icloser_bucket, + std::size_t(m_buckets[ito_move_closer_value].dist_from_ideal_bucket())); + + + tsl_assert(m_buckets[icloser_bucket].empty()); + const distance_type new_distance = distance_type(m_buckets[ito_move_closer_value].dist_from_ideal_bucket() - + (ito_move_closer_value - icloser_bucket)); + m_buckets[icloser_bucket].set_value_of_empty_bucket(new_distance, + m_buckets[ito_move_closer_value].truncated_hash(), + std::move(m_buckets[ito_move_closer_value].value())); + m_buckets[ito_move_closer_value].clear(); + + + ++icloser_bucket; + ++ito_move_closer_value; + } + + + return iterator(m_buckets.begin() + ireturn_bucket); + } + + + template + size_type erase(const K& key) { + return erase(key, hash_key(key)); + } + + template + size_type erase(const K& key, std::size_t hash) { + auto it = find(key, hash); + if(it != end()) { + erase_from_bucket(it); + + return 1; + } + else { + return 0; + } + } + + + + + + void swap(robin_hash& other) { + using std::swap; + + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(m_buckets, other.m_buckets); + swap(m_bucket_count, other.m_bucket_count); + swap(m_nb_elements, other.m_nb_elements); + swap(m_load_threshold, other.m_load_threshold); + swap(m_max_load_factor, other.m_max_load_factor); + swap(m_grow_on_next_insert, other.m_grow_on_next_insert); + } + + + /* + * Lookup + */ + template::value>::type* = nullptr> + typename U::value_type& at(const K& key) { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + typename U::value_type& at(const K& key, std::size_t hash) { + return const_cast(static_cast(this)->at(key, hash)); + } + + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key) const { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key, std::size_t hash) const { + auto it = find(key, hash); + if(it != cend()) { + return it.value(); + } + else { + THROW(std::out_of_range, "Couldn't find key."); + } + } + + template::value>::type* = nullptr> + typename U::value_type& operator[](K&& key) { + return try_emplace(std::forward(key)).first.value(); + } + + + template + size_type count(const K& key) const { + return count(key, hash_key(key)); + } + + template + size_type count(const K& key, std::size_t hash) const { + if(find(key, hash) != cend()) { + return 1; + } + else { + return 0; + } + } + + + template + iterator find(const K& key) { + return find_impl(key, hash_key(key)); + } + + template + iterator find(const K& key, std::size_t hash) { + return find_impl(key, hash); + } + + + template + const_iterator find(const K& key) const { + return find_impl(key, hash_key(key)); + } + + template + const_iterator find(const K& key, std::size_t hash) const { + return find_impl(key, hash); + } + + + template + std::pair equal_range(const K& key) { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) { + iterator it = find(key, hash); + return std::make_pair(it, (it == end())?it:std::next(it)); + } + + + template + std::pair equal_range(const K& key) const { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) const { + const_iterator it = find(key, hash); + return std::make_pair(it, (it == cend())?it:std::next(it)); + } + + /* + * Bucket interface + */ + size_type bucket_count() const { + return m_bucket_count; + } + + size_type max_bucket_count() const { + return std::min(GrowthPolicy::max_bucket_count(), m_buckets.max_size()); + } + + /* + * Hash policy + */ + float load_factor() const { + return float(m_nb_elements)/float(bucket_count()); + } + + float max_load_factor() const { + return m_max_load_factor; + } + + void max_load_factor(float ml) { + m_max_load_factor = std::max(0.1f, std::min(ml, 0.95f)); + m_load_threshold = size_type(float(bucket_count())*m_max_load_factor); + } + + void rehash(size_type count) { + count = std::max(count, size_type(std::ceil(float(size())/max_load_factor()))); + rehash_impl(count); + } + + void reserve(size_type count) { + rehash(size_type(std::ceil(float(count)/max_load_factor()))); + } + + /* + * Observers + */ + hasher hash_function() const { + return static_cast(*this); + } + + key_equal key_eq() const { + return static_cast(*this); + } + + + /* + * Other + */ + iterator mutable_iterator(const_iterator pos) { + return iterator(m_buckets.begin() + std::distance(m_buckets.cbegin(), pos.m_iterator)); + } + +private: + template + std::size_t hash_key(const K& key) const { + return Hash::operator()(key); + } + + template + bool compare_keys(const K1& key1, const K2& key2) const { + return KeyEqual::operator()(key1, key2); + } + + std::size_t bucket_for_hash(std::size_t hash) const { + return GrowthPolicy::bucket_for_hash(hash); + } + + template::value>::type* = nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_assert(index < bucket_count()); + + return (index + 1) & this->m_mask; + } + + template::value>::type* = nullptr> + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_assert(index < bucket_count()); + + index++; + return (index != bucket_count())?index:0; + } + + + + template + iterator find_impl(const K& key, std::size_t hash) { + return mutable_iterator(static_cast(this)->find(key, hash)); + } + + template + const_iterator find_impl(const K& key, std::size_t hash) const { + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + if (TSL_LIKELY((!USE_STORED_HASH_ON_LOOKUP || m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key))) + { + return const_iterator(m_buckets.begin() + ibucket); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + return cend(); + } + + void erase_from_bucket(iterator pos) { + pos.m_iterator->clear(); + m_nb_elements--; + + /** + * Backward shift, swap the empty bucket, previous_ibucket, with the values on its right, ibucket, + * until we cross another empty bucket or if the other bucket has a distance_from_ideal_bucket == 0. + * + * We try to move the values closer to their ideal bucket. + */ + std::size_t previous_ibucket = std::size_t(std::distance(m_buckets.begin(), pos.m_iterator)); + std::size_t ibucket = next_bucket(previous_ibucket); + + while(m_buckets[ibucket].dist_from_ideal_bucket() > 0) { + tsl_assert(m_buckets[previous_ibucket].empty()); + + const distance_type new_distance = distance_type(m_buckets[ibucket].dist_from_ideal_bucket() - 1); + m_buckets[previous_ibucket].set_value_of_empty_bucket(new_distance, m_buckets[ibucket].truncated_hash(), + std::move(m_buckets[ibucket].value())); + m_buckets[ibucket].clear(); + + previous_ibucket = ibucket; + ibucket = next_bucket(ibucket); + } + } + + template + std::pair insert_impl(const K& key, Args&&... value_type_args) { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + distance_type dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + if((!USE_STORED_HASH_ON_LOOKUP || m_buckets[ibucket].bucket_hash_equal(hash)) && + compare_keys(KeySelect()(m_buckets[ibucket].value()), key)) + { + return std::make_pair(iterator(m_buckets.begin() + ibucket), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + + while(dist_from_ideal_bucket <= m_buckets[ibucket].dist_from_ideal_bucket()) { + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + } + + + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } + else { + insert_value(ibucket, dist_from_ideal_bucket, bucket_entry::truncate_hash(hash), + std::forward(value_type_args)...); + } + + + m_nb_elements++; + /* + * The value will be inserted in ibucket in any case, either because it was + * empty or by stealing the bucket (robin hood). + */ + return std::make_pair(iterator(m_buckets.begin() + ibucket), true); + } + + + template + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, Args&&... value_type_args) + { + value_type value(std::forward(value_type_args)...); + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + // fix issue #6 (see https://github.com/Tessil/robin-map/commit/965dacd191502d310f053cc00551ea8fc2f6c7f0) + void insert_value(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) + { + insert_value_impl(ibucket, dist_from_ideal_bucket, hash, value); + } + + /* + * We don't use `value_type&& value` as last argument due to a bug in MSVC when `value_type` is a pointer, + * The compiler is not able to see the difference between `std::string*` and `std::string*&&` resulting in + * compile error. + * + * The `value` will be in a moved state at the end of the function. + */ + void insert_value_impl(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type& value) + { + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + + while(!m_buckets[ibucket].empty()) { + if(dist_from_ideal_bucket > m_buckets[ibucket].dist_from_ideal_bucket()) { + if(dist_from_ideal_bucket >= REHASH_ON_HIGH_NB_PROBES__NPROBES && + load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) + { + /** + * The number of probes is really high, rehash the map on the next insert. + * Difficult to do now as rehash may throw. + */ + m_grow_on_next_insert = true; + } + + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, hash, std::move(value)); + } + + + void rehash_impl(size_type count) { + robin_hash new_table(count, static_cast(*this), static_cast(*this), + get_allocator(), m_max_load_factor); + + const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_table.bucket_count()); + for(auto& bucket: m_buckets) { + if(bucket.empty()) { + continue; + } + + const std::size_t hash = use_stored_hash?bucket.truncated_hash(): + new_table.hash_key(KeySelect()(bucket.value())); + + new_table.insert_value_on_rehash(new_table.bucket_for_hash(hash), 0, + bucket_entry::truncate_hash(hash), std::move(bucket.value())); + } + + new_table.m_nb_elements = m_nb_elements; + new_table.swap(*this); + } + + void insert_value_on_rehash(std::size_t ibucket, distance_type dist_from_ideal_bucket, + truncated_hash_type hash, value_type&& value) + { + while(true) { + if(dist_from_ideal_bucket > m_buckets[ibucket].dist_from_ideal_bucket()) { + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_value_of_empty_bucket(dist_from_ideal_bucket, hash, std::move(value)); + return; + } + else { + m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, value); + } + } + + dist_from_ideal_bucket++; + ibucket = next_bucket(ibucket); + } + } + + + + /** + * Return true if the map has been rehashed. + */ + bool grow_on_high_load() { + if(m_grow_on_next_insert || size() >= m_load_threshold) { + rehash_impl(GrowthPolicy::next_bucket_count()); + m_grow_on_next_insert = false; + + return true; + } + + return false; + } + + +public: + static const size_type DEFAULT_INIT_BUCKETS_SIZE = 16; + static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.5f; + +private: + static const distance_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128; + static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f; + +private: + buckets_container_type m_buckets; + + /** + * Used a lot in find, avoid the call to m_buckets.size() which is a bit slower. + */ + size_type m_bucket_count; + + size_type m_nb_elements; + + size_type m_load_threshold; + float m_max_load_factor; + + bool m_grow_on_next_insert; +}; + +} + +} + +#endif diff --git a/package/ios/libs/filament/include/tsl/robin_map.h b/package/ios/libs/filament/include/tsl/robin_map.h new file mode 100644 index 00000000..5958e70f --- /dev/null +++ b/package/ios/libs/filament/include/tsl/robin_map.h @@ -0,0 +1,668 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_MAP_H +#define TSL_ROBIN_MAP_H + + +#include +#include +#include +#include +#include +#include +#include "robin_hash.h" + + +namespace tsl { + + +/** + * Implementation of a hash map using open-adressing and the robin hood hashing algorithm with backward shift deletion. + * + * For operations modifying the hash map (insert, erase, rehash, ...), the strong exception guarantee + * is only guaranteed when the expression `std::is_nothrow_swappable>::value && + * std::is_nothrow_move_constructible>::value` is true, otherwise if an exception + * is thrown during the swap or the move, the hash map may end up in a undefined state. Per the standard + * a `Key` or `T` with a noexcept copy constructor and no move constructor also satisfies the + * `std::is_nothrow_move_constructible>::value` criterion (and will thus guarantee the + * strong exception for the map). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve + * the performance during lookups if the `KeyEqual` function takes time (if it engenders a cache-miss for example) + * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used + * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. + * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. + * `sizeof(tsl::detail_robin_hash::bucket_entry) == + * sizeof(tsl::detail_robin_hash::bucket_entry)`) and `tsl::rh::power_of_two_growth_policy` is + * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the map grows and consequently how a hash value is mapped to a bucket. + * By default the map uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets + * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo. + * Other growth policies are available and you may define your own growth policy, + * check `tsl::rh::power_of_two_growth_policy` for the interface. + * + * If the destructor of `Key` or `T` throws an exception, the behaviour of the class is undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_map { +private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const std::pair& key_value) const noexcept { + return key_value.first; + } + + key_type& operator()(std::pair& key_value) noexcept { + return key_value.first; + } + }; + + class ValueSelect { + public: + using value_type = T; + + const value_type& operator()(const std::pair& key_value) const noexcept { + return key_value.second; + } + + value_type& operator()(std::pair& key_value) noexcept { + return key_value.second; + } + }; + + using ht = detail_robin_hash::robin_hash, KeySelect, ValueSelect, + Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>; + +public: + using key_type = typename ht::key_type; + using mapped_type = T; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + +public: + /* + * Constructors + */ + robin_map(): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit robin_map(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + robin_map(size_type bucket_count, + const Allocator& alloc): robin_map(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_map(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_map(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit robin_map(const Allocator& alloc): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): robin_map(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): robin_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + robin_map(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_map(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + robin_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + robin_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_map(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + robin_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_map& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + template::value>::type* = nullptr> + std::pair insert(P&& value) { + return m_ht.emplace(std::forward

(value)); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert(hint, value); + } + + template::value>::type* = nullptr> + iterator insert(const_iterator hint, P&& value) { + return m_ht.emplace_hint(hint, std::forward

(value)); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert(hint, std::move(value)); + } + + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + + + + template + std::pair insert_or_assign(const key_type& k, M&& obj) { + return m_ht.insert_or_assign(k, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& k, M&& obj) { + return m_ht.insert_or_assign(std::move(k), std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { + return m_ht.insert_or_assign(hint, k, std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { + return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); + } + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + + template + std::pair try_emplace(const key_type& k, Args&&... args) { + return m_ht.try_emplace(k, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& k, Args&&... args) { + return m_ht.try_emplace(std::move(k), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { + return m_ht.try_emplace(hint, k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { + return m_ht.try_emplace(hint, std::move(k), std::forward(args)...); + } + + + + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(robin_map& other) { other.m_ht.swap(m_ht); } + + + + /* + * Lookup + */ + T& at(const Key& key) { return m_ht.at(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + const T& at(const Key& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const Key& key, std::size_t precalculated_hash) + */ + const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + T& at(const K& key) { return m_ht.at(key); } + + /** + * @copydoc at(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + /** + * @copydoc at(const K& key) + */ + template::value>::type* = nullptr> + const T& at(const K& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + + + T& operator[](const Key& key) { return m_ht[key]; } + T& operator[](Key&& key) { return m_ht[std::move(key)]; } + + + + + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + friend bool operator==(const robin_map& lhs, const robin_map& rhs) { + if(lhs.size() != rhs.size()) { + return false; + } + + for(const auto& element_lhs: lhs) { + const auto it_element_rhs = rhs.find(element_lhs.first); + if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) { + return false; + } + } + + return true; + } + + friend bool operator!=(const robin_map& lhs, const robin_map& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_map& lhs, robin_map& rhs) { + lhs.swap(rhs); + } + +private: + ht m_ht; +}; + + +/** + * Same as `tsl::robin_map`. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + bool StoreHash = false> +using robin_pg_map = robin_map; + +} // end namespace tsl + +#endif diff --git a/package/ios/libs/filament/include/tsl/robin_set.h b/package/ios/libs/filament/include/tsl/robin_set.h new file mode 100644 index 00000000..4e4667e2 --- /dev/null +++ b/package/ios/libs/filament/include/tsl/robin_set.h @@ -0,0 +1,535 @@ +/** + * MIT License + * + * Copyright (c) 2017 Tessil + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ROBIN_SET_H +#define TSL_ROBIN_SET_H + + +#include +#include +#include +#include +#include +#include +#include "robin_hash.h" + + +namespace tsl { + + +/** + * Implementation of a hash set using open-adressing and the robin hood hashing algorithm with backward shift deletion. + * + * For operations modifying the hash set (insert, erase, rehash, ...), the strong exception guarantee + * is only guaranteed when the expression `std::is_nothrow_swappable::value && + * std::is_nothrow_move_constructible::value` is true, otherwise if an exception + * is thrown during the swap or the move, the hash set may end up in a undefined state. Per the standard + * a `Key` with a noexcept copy constructor and no move constructor also satisfies the + * `std::is_nothrow_move_constructible::value` criterion (and will thus guarantee the + * strong exception for the set). + * + * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve + * the performance during lookups if the `KeyEqual` function takes time (or engenders a cache-miss for example) + * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used + * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. + * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. + * `sizeof(tsl::detail_robin_hash::bucket_entry) == + * sizeof(tsl::detail_robin_hash::bucket_entry)`) and `tsl::rh::power_of_two_growth_policy` is + * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will + * not be used on lookups unless `StoreHash` is true). + * + * `GrowthPolicy` defines how the set grows and consequently how a hash value is mapped to a bucket. + * By default the set uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets + * to a power of two and uses a mask to set the hash to a bucket instead of the slow modulo. + * Other growth policies are available and you may define your own growth policy, + * check `tsl::rh::power_of_two_growth_policy` for the interface. + * + * If the destructor of `Key` throws an exception, the behaviour of the class is undefined. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators. + * - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators. + * - erase: always invalidate the iterators. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + bool StoreHash = false, + class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>> +class robin_set { +private: + template + using has_is_transparent = tsl::detail_robin_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const Key& key) const noexcept { + return key; + } + + key_type& operator()(Key& key) noexcept { + return key; + } + }; + + using ht = detail_robin_hash::robin_hash; + +public: + using key_type = typename ht::key_type; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + + + /* + * Constructors + */ + robin_set(): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit robin_set(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + robin_set(size_type bucket_count, + const Allocator& alloc): robin_set(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_set(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_set(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit robin_set(const Allocator& alloc): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): robin_set(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + robin_set(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): robin_set(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + robin_set(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + robin_set& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + + std::pair insert(const value_type& value) { + return m_ht.insert(value); + } + + std::pair insert(value_type&& value) { + return m_ht.insert(std::move(value)); + } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { + m_ht.insert(first, last); + } + + void insert(std::initializer_list ilist) { + m_ht.insert(ilist.begin(), ilist.end()); + } + + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { + return m_ht.emplace(std::forward(args)...); + } + + + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + iterator erase(iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(robin_set& other) { other.m_ht.swap(m_ht); } + + + + /* + * Lookup + */ + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); } + + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + friend bool operator==(const robin_set& lhs, const robin_set& rhs) { + if(lhs.size() != rhs.size()) { + return false; + } + + for(const auto& element_lhs: lhs) { + const auto it_element_rhs = rhs.find(element_lhs); + if(it_element_rhs == rhs.cend()) { + return false; + } + } + + return true; + } + + friend bool operator!=(const robin_set& lhs, const robin_set& rhs) { + return !operator==(lhs, rhs); + } + + friend void swap(robin_set& lhs, robin_set& rhs) { + lhs.swap(rhs); + } + +private: + ht m_ht; +}; + + +/** + * Same as `tsl::robin_set`. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + bool StoreHash = false> +using robin_pg_set = robin_set; + +} // end namespace tsl + +#endif + diff --git a/package/ios/libs/filament/include/uberz/ArchiveEnums.h b/package/ios/libs/filament/include/uberz/ArchiveEnums.h new file mode 100644 index 00000000..b2741be9 --- /dev/null +++ b/package/ios/libs/filament/include/uberz/ArchiveEnums.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef UBERZ_ARCHIVE_ENUMS_H +#define UBERZ_ARCHIVE_ENUMS_H + +#include + +namespace filament::uberz { + + enum class ArchiveFeature : uint64_t { + UNSUPPORTED, + OPTIONAL, + REQUIRED, + }; + +} // namespace filament::uberz + +#endif // UBERZ_ARCHIVE_ENUMS_H diff --git a/package/ios/libs/filament/include/uberz/ReadableArchive.h b/package/ios/libs/filament/include/uberz/ReadableArchive.h new file mode 100644 index 00000000..5d78cb26 --- /dev/null +++ b/package/ios/libs/filament/include/uberz/ReadableArchive.h @@ -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. + */ + +#ifndef UBERZ_READABLE_ARCHIVE_H +#define UBERZ_READABLE_ARCHIVE_H + +#include + +#include + +#include + +namespace filament::uberz { + +// ArchiveSpec is a parse-free binary format. The client simply casts a word-aligned content blob +// into a ReadableArchive struct pointer, then calls the following function to convert all the +// offset fields into pointers. +void convertOffsetsToPointers(struct ReadableArchive* archive); + +UTILS_WARNING_PUSH +UTILS_WARNING_ENABLE_PADDED + +// Precompiled set of materials bundled with a list of features flags that each material supports. +// This is the readable counterpart to WriteableArchive. +// Used by gltfio; users do not need to access this class directly. +struct ReadableArchive { + uint32_t magic; + uint32_t version; + uint64_t specsCount; + union { + struct ArchiveSpec* specs; + uint64_t specsOffset; + }; +}; + +static constexpr Shading INVALID_SHADING_MODEL = (Shading) 0xff; +static constexpr BlendingMode INVALID_BLENDING = (BlendingMode) 0xff; + +struct ArchiveSpec { + Shading shadingModel; + BlendingMode blendingMode; + uint16_t flagsCount; + uint32_t packageByteCount; + union { + struct ArchiveFlag* flags; + uint64_t flagsOffset; + }; + union { + uint8_t* package; + uint64_t packageOffset; + }; +}; + +struct ArchiveFlag { + union { + const char* name; + uint64_t nameOffset; + }; + ArchiveFeature value; +}; + +UTILS_WARNING_POP + +} // namespace filament::uberz + +#endif // UBERZ_READABLE_ARCHIVE_H diff --git a/package/ios/libs/filament/include/uberz/WritableArchive.h b/package/ios/libs/filament/include/uberz/WritableArchive.h new file mode 100644 index 00000000..e511d95f --- /dev/null +++ b/package/ios/libs/filament/include/uberz/WritableArchive.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef UBERZ_WRITABLE_ARCHIVE_H +#define UBERZ_WRITABLE_ARCHIVE_H + +#include + +#include +#include +#include + +#include + +#include + +namespace filament::uberz { + +// Precompiled set of materials bundled with a list of features flags that each material supports. +// This is the writeable counterpart to ReadableArchive. +// Users do not need to access this class directly, they should go through gltfio. +class WritableArchive { +public: + WritableArchive(size_t materialCount) : mMaterials(uint32_t(materialCount)) { + assert(materialCount <= UINT_MAX); + } + + void addMaterial(const char* name, const uint8_t* package, size_t packageSize); + void addSpecLine(std::string_view line); + utils::FixedCapacityVector serialize() const; + + // Low-level alternatives to addSpecLine that do not involve parsing: + void setShadingModel(Shading sm); + void setBlendingModel(BlendingMode bm); + void setFeatureFlag(const char* key, ArchiveFeature value); + +private: + size_t mLineNumber = 1; + ssize_t mMaterialIndex = -1; + + struct Material { + utils::CString name; + utils::FixedCapacityVector package; + Shading shadingModel; + BlendingMode blendingMode; + tsl::robin_map flags; + }; + + utils::FixedCapacityVector mMaterials; +}; + +} // namespace filament::uberz + +#endif // UBERZ_WRITABLE_ARCHIVE_H diff --git a/package/ios/libs/filament/include/utils/Allocator.h b/package/ios/libs/filament/include/utils/Allocator.h new file mode 100644 index 00000000..073206f4 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Allocator.h @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_ALLOCATOR_H +#define TNT_UTILS_ALLOCATOR_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace utils { + +namespace pointermath { + +template +static inline P* add(P* a, T b) noexcept { + return (P*)(uintptr_t(a) + uintptr_t(b)); +} + +template +static inline P* align(P* p, size_t alignment) noexcept { + // alignment must be a power-of-two + assert_invariant(alignment && !(alignment & alignment-1)); + return (P*)((uintptr_t(p) + alignment - 1) & ~(alignment - 1)); +} + +template +static inline P* align(P* p, size_t alignment, size_t offset) noexcept { + P* const r = align(add(p, offset), alignment); + assert_invariant(r >= add(p, offset)); + return r; +} + +} + +/* ------------------------------------------------------------------------------------------------ + * LinearAllocator + * + * + Allocates blocks linearly + * + Cannot free individual blocks + * + Can free top of memory back up to a specified point + * + Doesn't call destructors + * ------------------------------------------------------------------------------------------------ + */ + +class LinearAllocator { +public: + // use memory area provided + LinearAllocator(void* begin, void* end) noexcept; + + template + explicit LinearAllocator(const AREA& area) : LinearAllocator(area.begin(), area.end()) { } + + // Allocators can't be copied + LinearAllocator(const LinearAllocator& rhs) = delete; + LinearAllocator& operator=(const LinearAllocator& rhs) = delete; + + // Allocators can be moved + LinearAllocator(LinearAllocator&& rhs) noexcept; + LinearAllocator& operator=(LinearAllocator&& rhs) noexcept; + + ~LinearAllocator() noexcept = default; + + // our allocator concept + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t), size_t extra = 0) UTILS_RESTRICT { + // branch-less allocation + void* const p = pointermath::align(current(), alignment, extra); + void* const c = pointermath::add(p, size); + bool const success = c <= end(); + set_current(success ? c : current()); + return success ? p : nullptr; + } + + // API specific to this allocator + void *getCurrent() UTILS_RESTRICT noexcept { + return current(); + } + + // free memory back to the specified point + void rewind(void* p) UTILS_RESTRICT noexcept { + assert_invariant(p >= mBegin && p < end()); + set_current(p); + } + + // frees all allocated blocks + void reset() UTILS_RESTRICT noexcept { + rewind(mBegin); + } + + size_t allocated() const UTILS_RESTRICT noexcept { + return mSize; + } + + size_t available() const UTILS_RESTRICT noexcept { + return mSize - mCur; + } + + void swap(LinearAllocator& rhs) noexcept; + + void *base() noexcept { return mBegin; } + void const *base() const noexcept { return mBegin; } + + void free(void*, size_t) UTILS_RESTRICT noexcept { } + +protected: + void* end() UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mSize); } + void const* end() const UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mSize); } + + void* current() UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mCur); } + void const* current() const UTILS_RESTRICT noexcept { return pointermath::add(mBegin, mCur); } + +private: + void set_current(void* p) UTILS_RESTRICT noexcept { + mCur = uint32_t(uintptr_t(p) - uintptr_t(mBegin)); + } + void* mBegin = nullptr; + uint32_t mSize = 0; + uint32_t mCur = 0; +}; + +/* ------------------------------------------------------------------------------------------------ + * HeapAllocator + * + * + uses malloc() for all allocations + * + frees blocks with free() + * ------------------------------------------------------------------------------------------------ + */ +class HeapAllocator { +public: + HeapAllocator() noexcept = default; + + template + explicit HeapAllocator(const AREA&) { } + + // our allocator concept + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)) { + return aligned_alloc(size, alignment); + } + + void free(void* p) noexcept { + aligned_free(p); + } + + void free(void* p, size_t) noexcept { + this->free(p); + } + + ~HeapAllocator() noexcept = default; + + void swap(HeapAllocator&) noexcept { } +}; + +/* ------------------------------------------------------------------------------------------------ + * LinearAllocatorWithFallback + * + * This is a LinearAllocator that falls back to a HeapAllocator when allocation fail. The Heap + * allocator memory is freed only when the LinearAllocator is reset or destroyed. + * ------------------------------------------------------------------------------------------------ + */ +class LinearAllocatorWithFallback : private LinearAllocator, private HeapAllocator { + std::vector mHeapAllocations; +public: + LinearAllocatorWithFallback(void* begin, void* end) noexcept + : LinearAllocator(begin, end) { + } + + template + explicit LinearAllocatorWithFallback(const AREA& area) + : LinearAllocatorWithFallback(area.begin(), area.end()) { + } + + ~LinearAllocatorWithFallback() noexcept { + LinearAllocatorWithFallback::reset(); + } + + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)); + + void *getCurrent() noexcept { + return LinearAllocator::getCurrent(); + } + + void rewind(void* p) noexcept { + if (p >= LinearAllocator::base() && p < LinearAllocator::end()) { + LinearAllocator::rewind(p); + } + } + + void reset() noexcept; + + void free(void*, size_t) noexcept { } + + bool isHeapAllocation(void* p) const noexcept { + return p < LinearAllocator::base() || p >= LinearAllocator::end(); + } +}; + +// ------------------------------------------------------------------------------------------------ + +class FreeList { +public: + FreeList() noexcept = default; + FreeList(void* begin, void* end, size_t elementSize, size_t alignment, size_t extra) noexcept; + FreeList(const FreeList& rhs) = delete; + FreeList& operator=(const FreeList& rhs) = delete; + FreeList(FreeList&& rhs) noexcept = default; + FreeList& operator=(FreeList&& rhs) noexcept = default; + + void* pop() noexcept { + Node* const head = mHead; + mHead = head ? head->next : nullptr; + // this could indicate a use after free + assert_invariant(!mHead || mHead >= mBegin && mHead < mEnd); + return head; + } + + void push(void* p) noexcept { + assert_invariant(p); + assert_invariant(p >= mBegin && p < mEnd); + // TODO: assert this is one of our pointer (i.e.: it's address match one of ours) + Node* const head = static_cast(p); + head->next = mHead; + mHead = head; + } + + void *getFirst() noexcept { + return mHead; + } + + struct Node { + Node* next; + }; + +private: + static Node* init(void* begin, void* end, + size_t elementSize, size_t alignment, size_t extra) noexcept; + + Node* mHead = nullptr; + +#ifndef NDEBUG + // These are needed only for debugging... + void* mBegin = nullptr; + void* mEnd = nullptr; +#endif +}; + +class AtomicFreeList { +public: + AtomicFreeList() noexcept = default; + AtomicFreeList(void* begin, void* end, + size_t elementSize, size_t alignment, size_t extra) noexcept; + AtomicFreeList(const AtomicFreeList& rhs) = delete; + AtomicFreeList& operator=(const AtomicFreeList& rhs) = delete; + + void* pop() noexcept { + Node* const pStorage = mStorage; + + HeadPtr currentHead = mHead.load(); + while (currentHead.offset >= 0) { + // The value of "pNext" we load here might already contain application data if another + // thread raced ahead of us. But in that case, the computed "newHead" will be discarded + // since compare_exchange_weak fails. Then this thread will loop with the updated + // value of currentHead, and try again. + Node* const pNext = pStorage[currentHead.offset].next.load(std::memory_order_relaxed); + const HeadPtr newHead{ pNext ? int32_t(pNext - pStorage) : -1, currentHead.tag + 1 }; + // In the rare case that the other thread that raced ahead of us already returned the + // same mHead we just loaded, but it now has a different "next" value, the tag field will not + // match, and compare_exchange_weak will fail and prevent that particular race condition. + if (mHead.compare_exchange_weak(currentHead, newHead)) { + // This assert needs to occur after we have validated that there was no race condition + // Otherwise, next might already contain application data, if another thread + // raced ahead of us after we loaded mHead, but before we loaded mHead->next. + assert_invariant(!pNext || pNext >= pStorage); + break; + } + } + void* p = (currentHead.offset >= 0) ? (pStorage + currentHead.offset) : nullptr; + assert_invariant(!p || p >= pStorage); + return p; + } + + void push(void* p) noexcept { + Node* const storage = mStorage; + assert_invariant(p && p >= storage); + Node* const node = static_cast(p); + HeadPtr currentHead = mHead.load(); + HeadPtr newHead = { int32_t(node - storage), currentHead.tag + 1 }; + do { + newHead.tag = currentHead.tag + 1; + Node* const n = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr; + node->next.store(n, std::memory_order_relaxed); + } while(!mHead.compare_exchange_weak(currentHead, newHead)); + } + + void* getFirst() noexcept { + return mStorage + mHead.load(std::memory_order_relaxed).offset; + } + + struct Node { + // This should be a regular (non-atomic) pointer, but this causes TSAN to complain + // about a data-race that exists but is benin. We always use this atomic<> in + // relaxed mode. + // The data race TSAN complains about is when a pop() is interrupted by a + // pop() + push() just after mHead->next is read -- it appears as though it is written + // without synchronization (by the push), however in that case, the pop's CAS will fail + // and things will auto-correct. + // + // Pop() | + // | | + // read head->next | + // | pop() + // | | + // | read head->next + // | CAS, tag++ + // | | + // | push() + // | | + // [TSAN: data-race here] write head->next + // | CAS, tag++ + // CAS fails + // | + // read head->next + // | + // CAS, tag++ + // + std::atomic next; + }; + +private: + // This struct is using a 32-bit offset into the arena rather than + // a direct pointer, because together with the 32-bit tag, it needs to + // fit into 8 bytes. If it was any larger, it would not be possible to + // access it atomically. + struct alignas(8) HeadPtr { + int32_t offset; + uint32_t tag; + }; + + std::atomic mHead{}; + + Node* mStorage = nullptr; +}; + +// ------------------------------------------------------------------------------------------------ + +template < + size_t ELEMENT_SIZE, + size_t ALIGNMENT = alignof(std::max_align_t), + size_t OFFSET = 0, + typename FREELIST = FreeList> +class PoolAllocator { + static_assert(ELEMENT_SIZE >= sizeof(typename FREELIST::Node), + "ELEMENT_SIZE must accommodate at least a FreeList::Node"); +public: + // our allocator concept + void* alloc(size_t size = ELEMENT_SIZE, + size_t alignment = ALIGNMENT, size_t offset = OFFSET) noexcept { + assert_invariant(size <= ELEMENT_SIZE); + assert_invariant(alignment <= ALIGNMENT); + assert_invariant(offset == OFFSET); + return mFreeList.pop(); + } + + void free(void* p, size_t = ELEMENT_SIZE) noexcept { + mFreeList.push(p); + } + + constexpr size_t getSize() const noexcept { return ELEMENT_SIZE; } + + PoolAllocator(void* begin, void* end) noexcept + : mFreeList(begin, end, ELEMENT_SIZE, ALIGNMENT, OFFSET) { + } + + PoolAllocator(void* begin, size_t size) noexcept + : mFreeList(begin, static_cast(begin) + size, ELEMENT_SIZE, ALIGNMENT, OFFSET) { + } + + template + explicit PoolAllocator(const AREA& area) noexcept + : PoolAllocator(area.begin(), area.end()) { + } + + // Allocators can't be copied + PoolAllocator(const PoolAllocator& rhs) = delete; + PoolAllocator& operator=(const PoolAllocator& rhs) = delete; + + // Allocators can be moved + PoolAllocator(PoolAllocator&& rhs) = default; + PoolAllocator& operator=(PoolAllocator&& rhs) = default; + + PoolAllocator() noexcept = default; + ~PoolAllocator() noexcept = default; + + // API specific to this allocator + + void *getCurrent() noexcept { + return mFreeList.getFirst(); + } + +private: + FREELIST mFreeList; +}; + +#define UTILS_MAX(a,b) ((a) > (b) ? (a) : (b)) + +template +using ObjectPoolAllocator = PoolAllocator; + +template +using ThreadSafeObjectPoolAllocator = PoolAllocator; + + +// ------------------------------------------------------------------------------------------------ +// Areas +// ------------------------------------------------------------------------------------------------ + +namespace AreaPolicy { + +class StaticArea { +public: + StaticArea() noexcept = default; + + StaticArea(void* b, void* e) noexcept + : mBegin(b), mEnd(e) { + } + + ~StaticArea() noexcept = default; + + StaticArea(const StaticArea& rhs) = default; + StaticArea& operator=(const StaticArea& rhs) = default; + StaticArea(StaticArea&& rhs) noexcept = default; + StaticArea& operator=(StaticArea&& rhs) noexcept = default; + + void* data() const noexcept { return mBegin; } + void* begin() const noexcept { return mBegin; } + void* end() const noexcept { return mEnd; } + size_t size() const noexcept { return uintptr_t(mEnd) - uintptr_t(mBegin); } + + friend void swap(StaticArea& lhs, StaticArea& rhs) noexcept { + using std::swap; + swap(lhs.mBegin, rhs.mBegin); + swap(lhs.mEnd, rhs.mEnd); + } + +private: + void* mBegin = nullptr; + void* mEnd = nullptr; +}; + +class HeapArea { +public: + HeapArea() noexcept = default; + + explicit HeapArea(size_t size) { + if (size) { + // TODO: policy committing memory + mBegin = malloc(size); + mEnd = pointermath::add(mBegin, size); + } + } + + ~HeapArea() noexcept { + // TODO: policy for returning memory to system + free(mBegin); + } + + HeapArea(const HeapArea& rhs) = delete; + HeapArea& operator=(const HeapArea& rhs) = delete; + HeapArea(HeapArea&& rhs) noexcept = delete; + HeapArea& operator=(HeapArea&& rhs) noexcept = delete; + + void* data() const noexcept { return mBegin; } + void* begin() const noexcept { return mBegin; } + void* end() const noexcept { return mEnd; } + size_t size() const noexcept { return uintptr_t(mEnd) - uintptr_t(mBegin); } + + friend void swap(HeapArea& lhs, HeapArea& rhs) noexcept { + using std::swap; + swap(lhs.mBegin, rhs.mBegin); + swap(lhs.mEnd, rhs.mEnd); + } + +private: + void* mBegin = nullptr; + void* mEnd = nullptr; +}; + +class NullArea { +public: + void* data() const noexcept { return nullptr; } + size_t size() const noexcept { return 0; } +}; + +} // namespace AreaPolicy + +// ------------------------------------------------------------------------------------------------ +// Policies +// ------------------------------------------------------------------------------------------------ + +namespace LockingPolicy { + +struct NoLock { + void lock() noexcept { } + void unlock() noexcept { } +}; + +using Mutex = utils::Mutex; + +} // namespace LockingPolicy + + +namespace TrackingPolicy { + +// default no-op tracker +struct Untracked { + Untracked() noexcept = default; + Untracked(const char* name, void* base, size_t size) noexcept { + (void)name, void(base), (void)size; + } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept { + (void)p, (void)size, (void)alignment, (void)extra; + } + void onFree(void* p, size_t = 0) noexcept { (void)p; } + void onReset() noexcept { } + void onRewind(void* addr) noexcept { (void)addr; } +}; + +// This just track the max memory usage and logs it in the destructor +struct HighWatermark { + HighWatermark() noexcept = default; + HighWatermark(const char* name, void* base, size_t size) noexcept + : mName(name), mBase(base), mSize(uint32_t(size)) { } + ~HighWatermark() noexcept; + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept; + void onFree(void* p, size_t size) noexcept; + void onReset() noexcept; + void onRewind(void const* addr) noexcept; + uint32_t getHighWatermark() const noexcept { return mHighWaterMark; } +protected: + const char* mName = nullptr; + void* mBase = nullptr; + uint32_t mSize = 0; + uint32_t mCurrent = 0; + uint32_t mHighWaterMark = 0; +}; + +// This just fills buffers with known values to help catch uninitialized access and use after free. +struct Debug { + Debug() noexcept = default; + Debug(const char* name, void* base, size_t size) noexcept + : mName(name), mBase(base), mSize(uint32_t(size)) { } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept; + void onFree(void* p, size_t size) noexcept; + void onReset() noexcept; + void onRewind(void* addr) noexcept; +protected: + const char* mName = nullptr; + void* mBase = nullptr; + uint32_t mSize = 0; +}; + +struct DebugAndHighWatermark : protected HighWatermark, protected Debug { + DebugAndHighWatermark() noexcept = default; + DebugAndHighWatermark(const char* name, void* base, size_t size) noexcept + : HighWatermark(name, base, size), Debug(name, base, size) { } + void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept { + HighWatermark::onAlloc(p, size, alignment, extra); + Debug::onAlloc(p, size, alignment, extra); + } + void onFree(void* p, size_t size) noexcept { + HighWatermark::onFree(p, size); + Debug::onFree(p, size); + } + void onReset() noexcept { + HighWatermark::onReset(); + Debug::onReset(); + } + void onRewind(void* addr) noexcept { + HighWatermark::onRewind(addr); + Debug::onRewind(addr); + } +}; + +} // namespace TrackingPolicy + +// ------------------------------------------------------------------------------------------------ +// Arenas +// ------------------------------------------------------------------------------------------------ + +template +class Arena { +public: + + Arena() = default; + + // construct an arena with a name and forward argument to its allocator + template + Arena(const char* name, size_t size, ARGS&& ... args) + : mArenaName(name), + mArea(size), + mAllocator(mArea, std::forward(args) ... ), + mListener(name, mArea.data(), mArea.size()) { + } + + template + Arena(const char* name, AreaPolicy&& area, ARGS&& ... args) + : mArenaName(name), + mArea(std::forward(area)), + mAllocator(mArea, std::forward(args) ... ), + mListener(name, mArea.data(), mArea.size()) { + } + + template + void* alloc(size_t size, size_t alignment, size_t extra, ARGS&& ... args) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment, extra, std::forward(args) ...); + mListener.onAlloc(p, size, alignment, extra); + return p; + } + + + // allocate memory from arena with given size and alignment + // (acceptable size/alignment may depend on the allocator provided) + void* alloc(size_t size, size_t alignment, size_t extra) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment, extra); + mListener.onAlloc(p, size, alignment, extra); + return p; + } + + void* alloc(size_t size, size_t alignment = alignof(std::max_align_t)) noexcept { + std::lock_guard guard(mLock); + void* p = mAllocator.alloc(size, alignment); + mListener.onAlloc(p, size, alignment, 0); + return p; + } + + // Allocate an array of trivially destructible objects + // for safety, we disable the object-based alloc method if the object type is not + // trivially destructible, since free() won't call the destructor and this is allocating + // an array. + template ::value>::type> + T* alloc(size_t count, size_t alignment, size_t extra) noexcept { + return (T*)alloc(count * sizeof(T), alignment, extra); + } + + template ::value>::type> + T* alloc(size_t count, size_t alignment = alignof(T)) noexcept { + return (T*)alloc(count * sizeof(T), alignment); + } + + // some allocators require more parameters + template + void free(void* p, size_t size, ARGS&& ... args) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p, size); + mAllocator.free(p, size, std::forward(args) ...); + } + } + + // some allocators require the size of the allocation for free + void free(void* p, size_t size) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p, size); + mAllocator.free(p, size); + } + } + + // return memory pointed by p to the arena + // (actual behaviour may depend on allocator provided) + void free(void* p) noexcept { + if (p) { + std::lock_guard guard(mLock); + mListener.onFree(p); + mAllocator.free(p); + } + } + + // some allocators don't have a free() call, but a single reset() or rewind() instead + void reset() noexcept { + std::lock_guard guard(mLock); + mListener.onReset(); + mAllocator.reset(); + } + + void* getCurrent() noexcept { return mAllocator.getCurrent(); } + + void rewind(void *addr) noexcept { + std::lock_guard guard(mLock); + mListener.onRewind(addr); + mAllocator.rewind(addr); + } + + // Allocate and construct an object + template + T* make(ARGS&& ... args) noexcept { + void* const p = this->alloc(sizeof(T), ALIGN); + return p ? new(p) T(std::forward(args)...) : nullptr; + } + + // destroys an object created with make() above, and frees associated memory + template + void destroy(T* p) noexcept { + if (p) { + p->~T(); + this->free((void*)p, sizeof(T)); + } + } + + char const* getName() const noexcept { return mArenaName; } + + AllocatorPolicy& getAllocator() noexcept { return mAllocator; } + AllocatorPolicy const& getAllocator() const noexcept { return mAllocator; } + + TrackingPolicy& getListener() noexcept { return mListener; } + TrackingPolicy const& getListener() const noexcept { return mListener; } + + AreaPolicy& getArea() noexcept { return mArea; } + AreaPolicy const& getArea() const noexcept { return mArea; } + + void setListener(TrackingPolicy listener) noexcept { + std::swap(mListener, listener); + } + + template + void emplaceListener(ARGS&& ... args) noexcept { + mListener.~TrackingPolicy(); + new (&mListener) TrackingPolicy(std::forward(args)...); + } + + // An arena can't be copied + Arena(Arena const& rhs) noexcept = delete; + Arena& operator=(Arena const& rhs) noexcept = delete; + + friend void swap(Arena& lhs, Arena& rhs) noexcept { + using std::swap; + swap(lhs.mArea, rhs.mArea); + swap(lhs.mAllocator, rhs.mAllocator); + swap(lhs.mLock, rhs.mLock); + swap(lhs.mListener, rhs.mListener); + swap(lhs.mArenaName, rhs.mArenaName); + } + +private: + char const* mArenaName = nullptr; + AreaPolicy mArea; + // note: we should use something like compressed_pair for the members below + AllocatorPolicy mAllocator; + LockingPolicy mLock; + TrackingPolicy mListener; +}; + +// ------------------------------------------------------------------------------------------------ + +template +using HeapArena = Arena; + +// ------------------------------------------------------------------------------------------------ + +// This doesn't implement our allocator concept, because it's too risky to use this as an allocator +// in particular, doing ArenaScope. +template +class ArenaScope { + + struct Finalizer { + void (*finalizer)(void* p) = nullptr; + Finalizer* next = nullptr; + }; + + template + static void destruct(void* p) noexcept { + static_cast(p)->~T(); + } + +public: + using Arena = ARENA; + + explicit ArenaScope(ARENA& allocator) + : mArena(allocator), mRewind(allocator.getCurrent()) { + } + + ArenaScope& operator=(const ArenaScope& rhs) = delete; + ArenaScope(ArenaScope&& rhs) noexcept = delete; + ArenaScope& operator=(ArenaScope&& rhs) noexcept = delete; + + ~ArenaScope() { + // run the finalizer chain + Finalizer* head = mFinalizerHead; + while (head) { + void* p = pointermath::add(head, sizeof(Finalizer)); + head->finalizer(p); + head = head->next; + } + // ArenaScope works only with Arena that implements rewind() + mArena.rewind(mRewind); + } + + template + T* make(ARGS&& ... args) noexcept { + T* o = nullptr; + if (std::is_trivially_destructible::value) { + o = mArena.template make(std::forward(args)...); + } else { + void* const p = (Finalizer*)mArena.alloc(sizeof(T), ALIGN, sizeof(Finalizer)); + if (p != nullptr) { + Finalizer* const f = static_cast(p) - 1; + // constructor must be called before adding the dtor to the list + // so that the ctor can allocate objects in a nested scope and have the + // finalizers called in reverse order. + o = new(p) T(std::forward(args)...); + f->finalizer = &destruct; + f->next = mFinalizerHead; + mFinalizerHead = f; + } + } + return o; + } + + void* allocate(size_t size, size_t alignment = 1) noexcept { + return mArena.template alloc(size, alignment, 0); + } + + template + T* allocate(size_t size, size_t alignment = alignof(T), size_t extra = 0) noexcept { + return mArena.template alloc(size, alignment, extra); + } + + // use with caution + ARENA& getArena() noexcept { return mArena; } + +private: + ARENA& mArena; + void* mRewind = nullptr; + Finalizer* mFinalizerHead = nullptr; +}; + + +template +class STLAllocator { +public: + using value_type = TYPE; + using pointer = TYPE*; + using const_pointer = const TYPE*; + using reference = TYPE&; + using const_reference = const TYPE&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + template + struct rebind { using other = STLAllocator; }; + +public: + // we don't make this explicit, so that we can initialize a vector using a STLAllocator + // from an Arena, avoiding to have to repeat the vector type. + STLAllocator(ARENA& arena) : mArena(arena) { } // NOLINT(google-explicit-constructor) + + template + explicit STLAllocator(STLAllocator const& rhs) : mArena(rhs.mArena) { } + + TYPE* allocate(std::size_t n) { + auto p = static_cast(mArena.alloc(n * sizeof(TYPE), alignof(TYPE))); + assert_invariant(p); + return p; + } + + void deallocate(TYPE* p, std::size_t n) { + mArena.free(p, n * sizeof(TYPE)); + } + + // these should be out-of-class friends, but this doesn't seem to work with some compilers + // which complain about multiple definition each time a STLAllocator<> is instantiated. + template + bool operator==(const STLAllocator& rhs) const noexcept { + return std::addressof(mArena) == std::addressof(rhs.mArena); + } + + template + bool operator!=(const STLAllocator& rhs) const noexcept { + return !operator==(rhs); + } + +private: + template + friend class STLAllocator; + + ARENA& mArena; +}; + +} // namespace utils + +#endif // TNT_UTILS_ALLOCATOR_H diff --git a/package/ios/libs/filament/include/utils/BitmaskEnum.h b/package/ios/libs/filament/include/utils/BitmaskEnum.h new file mode 100644 index 00000000..17f94d21 --- /dev/null +++ b/package/ios/libs/filament/include/utils/BitmaskEnum.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_UTILS_BITMASKENUM_H +#define TNT_UTILS_BITMASKENUM_H + +#include // for std::false_type + +#include +#include + +namespace utils { + +template +struct EnableBitMaskOperators : public std::false_type { }; + +template +struct EnableIntegerOperators : public std::false_type { }; + +namespace Enum { + +template +size_t count(); + +} // namespace enum +} // namespace utils + +// ------------------------------------------------------------------------------------------------ + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr int operator+(Enum value) noexcept { + return int(value); +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator==(Enum lhs, size_t rhs) noexcept { + using underlying_t = std::underlying_type_t; + return underlying_t(lhs) == rhs; +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator==(size_t lhs, Enum rhs) noexcept { + return rhs == lhs; +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator!=(Enum lhs, size_t rhs) noexcept { + return !(rhs == lhs); +} + +template::value && utils::EnableIntegerOperators::value, int> = 0> +inline constexpr bool operator!=(size_t lhs, Enum rhs) noexcept { + return rhs != lhs; +} + +// ------------------------------------------------------------------------------------------------ + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool operator!(Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return underlying(rhs) == 0; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator~(Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(~underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator|(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) | underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator&(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) & underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator^(Enum lhs, Enum rhs) noexcept { + using underlying = std::underlying_type_t; + return Enum(underlying(lhs) ^ underlying(rhs)); +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator|=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs | rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator&=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs & rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr Enum operator^=(Enum& lhs, Enum rhs) noexcept { + return lhs = lhs ^ rhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool none(Enum lhs) noexcept { + return !lhs; +} + +template::value && utils::EnableBitMaskOperators::value, int> = 0> +inline constexpr bool any(Enum lhs) noexcept { + return !none(lhs); +} + +#endif // TNT_UTILS_BITMASKENUM_H diff --git a/package/ios/libs/filament/include/utils/CString.h b/package/ios/libs/filament/include/utils/CString.h new file mode 100644 index 00000000..d5b76951 --- /dev/null +++ b/package/ios/libs/filament/include/utils/CString.h @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_CSTRING_H +#define TNT_UTILS_CSTRING_H + +// NOTE: this header should not include STL headers + +#include + +#include +#include +#include +#include +#include + +namespace utils { + +//! \privatesection +struct hashCStrings { + typedef const char* argument_type; + typedef size_t result_type; + result_type operator()(argument_type cstr) const noexcept { + size_t hash = 5381; + while (int const c = *cstr++) { + hash = (hash * 33u) ^ size_t(c); + } + return hash; + } +}; + +template +using StringLiteral = const char[N]; + + +// ------------------------------------------------------------------------------------------------ + +class UTILS_PUBLIC CString { +public: + using value_type = char; + using size_type = uint32_t; + using difference_type = int32_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = value_type*; + using const_iterator = const value_type*; + + CString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug + + // Allocates memory and appends a null. This constructor can be used to hold arbitrary data + // inside the string (i.e. it can contain nulls or non-ASCII encodings). + CString(const char* cstr, size_t length); + + // Allocates memory for a string of size length plus space for the null terminating character. + // Also initializes the memory to 0. This constructor can be used to hold arbitrary data + // inside the string. + explicit CString(size_t length); + + // Allocates memory and copies traditional C string content. Unlike the above constructor, this + // does not allow embedded nulls. This is explicit because this operation is costly. + explicit CString(const char* cstr); + + template + CString(StringLiteral const& other) noexcept // NOLINT(google-explicit-constructor) + : CString(other, N - 1) { + } + + CString(const CString& rhs); + + CString(CString&& rhs) noexcept { + this->swap(rhs); + } + + + CString& operator=(const CString& rhs); + + CString& operator=(CString&& rhs) noexcept { + this->swap(rhs); + return *this; + } + + ~CString() noexcept { + if (mData) { + free(mData - 1); + } + } + + void swap(CString& other) noexcept { + // don't use std::swap(), we don't want an STL dependency in this file + auto *temp = mCStr; + mCStr = other.mCStr; + other.mCStr = temp; + } + + const_pointer c_str() const noexcept { return mCStr; } + pointer c_str() noexcept { return mCStr; } + const_pointer c_str_safe() const noexcept { return mData ? c_str() : ""; } + const_pointer data() const noexcept { return c_str(); } + pointer data() noexcept { return c_str(); } + size_type size() const noexcept { return mData ? mData[-1].length : 0; } + size_type length() const noexcept { return size(); } + bool empty() const noexcept { return size() == 0; } + + iterator begin() noexcept { return mCStr; } + iterator end() noexcept { return begin() + length(); } + const_iterator begin() const noexcept { return data(); } + const_iterator end() const noexcept { return begin() + length(); } + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + + CString& replace(size_type pos, size_type len, const CString& str) noexcept; + CString& insert(size_type pos, const CString& str) noexcept { return replace(pos, 0, str); } + + const_reference operator[](size_type pos) const noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference operator[](size_type pos) noexcept { + assert(pos < size()); + return begin()[pos]; + } + + const_reference at(size_type pos) const noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference at(size_type pos) noexcept { + assert(pos < size()); + return begin()[pos]; + } + + reference front() noexcept { + assert(size()); + return begin()[0]; + } + + const_reference front() const noexcept { + assert(size()); + return begin()[0]; + } + + reference back() noexcept { + assert(size()); + return begin()[size() - 1]; + } + + const_reference back() const noexcept { + assert(size()); + return begin()[size() - 1]; + } + + // placement new declared as "throw" to avoid the compiler's null-check + inline void* operator new(size_t, void* ptr) { + assert(ptr); + return ptr; + } + + struct Hasher : private hashCStrings { + typedef CString argument_type; + typedef size_t result_type; + result_type operator()(const argument_type& s) const noexcept { + return hashCStrings::operator()(s.c_str()); + } + }; + +private: + struct Data { + size_type length; + }; + + // mCStr points to the C-string or nullptr. if non-null, mCStr is preceded by the string's size + union { + value_type *mCStr = nullptr; + Data* mData; // Data is stored at mData[-1] + }; + + int compare(const CString& rhs) const noexcept { + size_type const lhs_size = size(); + size_type const rhs_size = rhs.size(); + if (lhs_size < rhs_size) return -1; + if (lhs_size > rhs_size) return 1; + return strncmp(data(), rhs.data(), size()); + } + + friend bool operator==(CString const& lhs, CString const& rhs) noexcept { + return (lhs.data() == rhs.data()) || + ((lhs.size() == rhs.size()) && !strncmp(lhs.data(), rhs.data(), lhs.size())); + } + friend bool operator!=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs == rhs); + } + friend bool operator<(CString const& lhs, CString const& rhs) noexcept { + return lhs.compare(rhs) < 0; + } + friend bool operator>(CString const& lhs, CString const& rhs) noexcept { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs < rhs); + } + friend bool operator<=(CString const& lhs, CString const& rhs) noexcept { + return !(lhs > rhs); + } +}; + +// implement this for your type for automatic conversion to CString. Failing to do so leads +// to a compile-time failure. +template +CString to_string(T value) noexcept; + +// ------------------------------------------------------------------------------------------------ + +template +class UTILS_PUBLIC FixedSizeString { +public: + using value_type = char; + using pointer = value_type*; + using const_pointer = const value_type*; + static_assert(N > 0); + + FixedSizeString() noexcept = default; + explicit FixedSizeString(const char* str) noexcept { + strncpy(mData, str, N - 1); // leave room for the null terminator + } + + const_pointer c_str() const noexcept { return mData; } + pointer c_str() noexcept { return mData; } + +private: + value_type mData[N] = {0}; +}; + +} // namespace utils + +#endif // TNT_UTILS_CSTRING_H diff --git a/package/ios/libs/filament/include/utils/CallStack.h b/package/ios/libs/filament/include/utils/CallStack.h new file mode 100644 index 00000000..33ac0b50 --- /dev/null +++ b/package/ios/libs/filament/include/utils/CallStack.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef UTILS_CALLSTACK_H +#define UTILS_CALLSTACK_H + +#include +#include +#include + +#include +#include +#include + +namespace utils { + +/** + * CallStack captures the current's thread call stack. + */ +class CallStack { +public: + /** + * Creates an empty call stack + * @see CallStack::capture() + */ + CallStack() = default; + CallStack(const CallStack&) = default; + ~CallStack() = default; + + /** + * A convenience method to create and capture the stack trace in one go. + * @param ignore number frames to ignore at the top of the stack. + * @return A CallStack object + */ + static CallStack unwind(size_t ignore = 0) noexcept; + + /** + * Capture the current thread's stack and replaces the existing one if any. + * @param ignore number frames to ignore at the top of the stack. + */ + void update(size_t ignore = 0) noexcept; + + /** + * Get the number of stack frames this object has recorded. + * @return How many stack frames are accessible through operator[] + */ + size_t getFrameCount() const noexcept; + + /** + * Return the program-counter of each stack frame captured + * @param index of the frame between 0 and getFrameCount()-1 + * @return the program-counter of the stack-frame recorded at index \p index + * @throw std::out_of_range if the index is out of range + */ + intptr_t operator [](size_t index) const; + + /** Demangles a C++ type name */ + static utils::CString demangleTypeName(const char* mangled); + + template + static utils::CString typeName() { +#if UTILS_HAS_RTTI + return demangleTypeName(typeid(T).name()); +#else + return CString(""); +#endif + } + + /** + * Outputs a CallStack into a stream. + * This will print, when possible, the demangled names of functions corresponding to the + * program-counter recorded. + */ + friend utils::io::ostream& operator <<(utils::io::ostream& stream, const CallStack& callstack); + + bool operator <(const CallStack& rhs) const; + + inline bool operator >(const CallStack& rhs) const { + return rhs < *this; + } + + inline bool operator !=(const CallStack& rhs) const { + return *this < rhs || rhs < *this; + } + + inline bool operator >=(const CallStack& rhs) const { + return !operator <(rhs); + } + + inline bool operator <=(const CallStack& rhs) const { + return !operator >(rhs); + } + + inline bool operator ==(const CallStack& rhs) const { + return !operator !=(rhs); + } + +private: + void update_gcc(size_t ignore) noexcept; + + static utils::CString demangle(const char* mangled); + + static constexpr size_t NUM_FRAMES = 20; + + struct StackFrameInfo { + intptr_t pc; + }; + + size_t m_frame_count = 0; + StackFrameInfo m_stack[NUM_FRAMES]; +}; + +} // namespace utils + +#endif // UTILS_CALLSTACK_H diff --git a/package/ios/libs/filament/include/utils/Entity.h b/package/ios/libs/filament/include/utils/Entity.h new file mode 100644 index 00000000..58fdf606 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Entity.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITY_H +#define TNT_UTILS_ENTITY_H + +#include + +#include +#include + +namespace utils { + +class UTILS_PUBLIC Entity { +public: + // this can be used to create an array of to-be-filled entities (see create()) + Entity() noexcept { } // NOLINT(modernize-use-equals-default), Ubuntu compiler bug + + // Entities can be copied + Entity(const Entity& e) noexcept = default; + Entity(Entity&& e) noexcept = default; + Entity& operator=(const Entity& e) noexcept = default; + Entity& operator=(Entity&& e) noexcept = default; + + // Entities can be compared + bool operator==(Entity e) const { return e.mIdentity == mIdentity; } + bool operator!=(Entity e) const { return e.mIdentity != mIdentity; } + + // Entities can be sorted + bool operator<(Entity e) const { return e.mIdentity < mIdentity; } + + bool isNull() const noexcept { + return mIdentity == 0; + } + + // an id that can be used for debugging/printing + uint32_t getId() const noexcept { + return mIdentity; + } + + explicit operator bool() const noexcept { return !isNull(); } + + void clear() noexcept { mIdentity = 0; } + + // Exports an entity to an int32_t which can be used "as is" in the Java programing language. + static int32_t smuggle(Entity entity) noexcept { + return int32_t(entity.getId()); + } + + // Imports an entity from an int32_t generated by smuggle() above. + static Entity import(int32_t identity) noexcept { + return Entity{ Type(identity) }; + } + + struct Hasher { + typedef Entity argument_type; + typedef size_t result_type; + result_type operator()(argument_type const& e) const { + return e.getId(); + } + }; + +private: + friend class EntityManager; + friend class EntityManagerImpl; + using Type = uint32_t; + + explicit Entity(Type identity) noexcept : mIdentity(identity) { } + + Type mIdentity = 0; +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITY_H diff --git a/package/ios/libs/filament/include/utils/EntityInstance.h b/package/ios/libs/filament/include/utils/EntityInstance.h new file mode 100644 index 00000000..75419493 --- /dev/null +++ b/package/ios/libs/filament/include/utils/EntityInstance.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITYINSTANCE_H +#define TNT_UTILS_ENTITYINSTANCE_H + +#include + +#include + +#include + +namespace utils { + +class UTILS_PUBLIC EntityInstanceBase { +public: + using Type = uint32_t; +protected: + Type mInstance = 0; +}; + +template +class UTILS_PUBLIC EntityInstance : public EntityInstanceBase { +public: + // default Instance is invalid + constexpr EntityInstance() noexcept = default; + + // check if this Instance is valid + constexpr bool isValid() const noexcept { return mInstance != 0; } + + // Instances of same type can be copied/assigned + constexpr EntityInstance(EntityInstance const& other) noexcept = default; + constexpr EntityInstance& operator=(EntityInstance const& other) noexcept = default; + + // EDIT instances can be converted to "read" Instances of same type + template > + constexpr explicit EntityInstance(EntityInstance const& other) noexcept { + mInstance = other.asValue(); + } + template > + EntityInstance& operator=(EntityInstance const& other) noexcept { + mInstance = other.asValue(); + return *this; + } + + // Instances can be compared + constexpr bool operator!=(EntityInstance e) const { return mInstance != e.mInstance; } + constexpr bool operator==(EntityInstance e) const { return mInstance == e.mInstance; } + + // Instances can be sorted + constexpr bool operator<(EntityInstance e) const { return mInstance < e.mInstance; } + constexpr bool operator<=(EntityInstance e) const { return mInstance <= e.mInstance; } + constexpr bool operator>(EntityInstance e) const { return mInstance > e.mInstance; } + constexpr bool operator>=(EntityInstance e) const { return mInstance >= e.mInstance; } + + // and we can iterate + constexpr EntityInstance& operator++() noexcept { ++mInstance; return *this; } + constexpr EntityInstance& operator--() noexcept { --mInstance; return *this; } + constexpr const EntityInstance operator++(int) const noexcept { return EntityInstance{ mInstance + 1 }; } + constexpr const EntityInstance operator--(int) const noexcept { return EntityInstance{ mInstance - 1 }; } + + + // return a value for this Instance (mostly needed for debugging + constexpr uint32_t asValue() const noexcept { return mInstance; } + + // auto convert to Type, so it can be used as an index + constexpr operator Type() const noexcept { return mInstance; } // NOLINT(google-explicit-constructor) + + // conversion from Type so we can initialize from an index + constexpr EntityInstance(Type value) noexcept { mInstance = value; } // NOLINT(google-explicit-constructor) +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITYINSTANCE_H diff --git a/package/ios/libs/filament/include/utils/EntityManager.h b/package/ios/libs/filament/include/utils/EntityManager.h new file mode 100644 index 00000000..5e2eaa1b --- /dev/null +++ b/package/ios/libs/filament/include/utils/EntityManager.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ENTITYMANAGER_H +#define TNT_UTILS_ENTITYMANAGER_H + +#include +#include + +#include +#include +#include + +#ifndef FILAMENT_UTILS_TRACK_ENTITIES +#define FILAMENT_UTILS_TRACK_ENTITIES false +#endif + +#if FILAMENT_UTILS_TRACK_ENTITIES +#include +#include +#endif + +namespace utils { + +class UTILS_PUBLIC EntityManager { +public: + // Get the global EntityManager. It is recommended to cache this value. + // Thread Safe. + static EntityManager& get() noexcept; + + class Listener { + public: + virtual void onEntitiesDestroyed(size_t n, Entity const* entities) noexcept = 0; + protected: + virtual ~Listener() noexcept; + }; + + // maximum number of entities that can exist at the same time + static size_t getMaxEntityCount() noexcept { + // because index 0 is reserved, we only have 2^GENERATION_SHIFT - 1 valid indices + return RAW_INDEX_COUNT - 1; + } + + // number of active Entities + size_t getEntityCount() const noexcept; + + // Create n entities. Thread safe. + void create(size_t n, Entity* entities); + + // destroys n entities. Thread safe. + void destroy(size_t n, Entity* entities) noexcept; + + // Create a new Entity. Thread safe. + // Return Entity.isNull() if the entity cannot be allocated. + Entity create() { + Entity e; + create(1, &e); + return e; + } + + // Destroys an Entity. Thread safe. + void destroy(Entity e) noexcept { + destroy(1, &e); + } + + // Return whether the given Entity has been destroyed (false) or not (true). + // Thread safe. + bool isAlive(Entity e) const noexcept { + assert(getIndex(e) < RAW_INDEX_COUNT); + return (!e.isNull()) && (getGeneration(e) == mGens[getIndex(e)]); + } + + // Registers a listener to be called when an entity is destroyed. Thread safe. + // If the listener is already registered, this method has no effect. + void registerListener(Listener* l) noexcept; + + // unregisters a listener. + void unregisterListener(Listener* l) noexcept; + + + /* no user serviceable parts below */ + + // current generation of the given index. Use for debugging and testing. + uint8_t getGenerationForIndex(size_t index) const noexcept { + return mGens[index]; + } + + // singleton, can't be copied + EntityManager(const EntityManager& rhs) = delete; + EntityManager& operator=(const EntityManager& rhs) = delete; + +#if FILAMENT_UTILS_TRACK_ENTITIES + std::vector getActiveEntities() const; + void dumpActiveEntities(utils::io::ostream& out) const; +#endif + +private: + friend class EntityManagerImpl; + EntityManager(); + ~EntityManager(); + + // GENERATION_SHIFT determines how many simultaneous Entities are available, the + // minimum memory requirement is 2^GENERATION_SHIFT bytes. + static constexpr const int GENERATION_SHIFT = 17; + static constexpr const size_t RAW_INDEX_COUNT = (1 << GENERATION_SHIFT); + static constexpr const Entity::Type INDEX_MASK = (1 << GENERATION_SHIFT) - 1u; + + static inline Entity::Type getGeneration(Entity e) noexcept { + return e.getId() >> GENERATION_SHIFT; + } + static inline Entity::Type getIndex(Entity e) noexcept { + return e.getId() & INDEX_MASK; + } + static inline Entity::Type makeIdentity(Entity::Type g, Entity::Type i) noexcept { + return (g << GENERATION_SHIFT) | (i & INDEX_MASK); + } + + // stores the generation of each index. + uint8_t * const mGens; +}; + +} // namespace utils + +#endif // TNT_UTILS_ENTITYMANAGER_H diff --git a/package/ios/libs/filament/include/utils/FixedCapacityVector.h b/package/ios/libs/filament/include/utils/FixedCapacityVector.h new file mode 100644 index 00000000..f3990124 --- /dev/null +++ b/package/ios/libs/filament/include/utils/FixedCapacityVector.h @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_FIXEDCAPACITYVECTOR_H +#define TNT_UTILS_FIXEDCAPACITYVECTOR_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef NDEBUG +#define FILAMENT_FORCE_CAPACITY_CHECK true +#else +#define FILAMENT_FORCE_CAPACITY_CHECK false +#endif + +namespace utils { + +/** + * FixedCapacityVector is (almost) a drop-in replacement for std::vector<> except it has a + * fixed capacity decided at runtime. The vector storage is never reallocated unless reserve() + * is called. Operations that add elements to the vector can fail if there is not enough + * capacity. + * + * An empty vector with a given capacity is created with + * FixedCapacityVector::with_capacity( capacity ); + * + * NOTE: When passing an initial size into the FixedCapacityVector constructor, default construction + * of the elements is skipped when their construction is trivial. This behavior is different from + * std::vector. e.g., std::vector(4) constructs 4 zeros while FixedCapacityVector(4) + * allocates 4 uninitialized values. Note that zero initialization is easily achieved by passing in + * the optional value argument, e.g. FixedCapacityVector(4, 0) or foo.resize(4, 0). + */ +template, bool CapacityCheck = true> +class UTILS_PUBLIC FixedCapacityVector { +public: + using allocator_type = A; + using value_type = T; + using reference = T&; + using const_reference = T const&; + using size_type = uint32_t; + using difference_type = int32_t; + using pointer = T*; + using const_pointer = T const*; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + +private: + using storage_traits = std::allocator_traits; + +public: + /** returns an empty vector with the specified capacity */ + static FixedCapacityVector with_capacity( + size_type capacity, const allocator_type& allocator = allocator_type()) { + return FixedCapacityVector(construct_with_capacity, capacity, allocator); + } + + FixedCapacityVector() = default; + + explicit FixedCapacityVector(const allocator_type& allocator) noexcept + : mCapacityAllocator({}, allocator) { + } + + explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type()) + : mSize(size), + mCapacityAllocator(size, allocator) { + mData = this->allocator().allocate(this->capacity()); + construct(begin(), end()); + } + + FixedCapacityVector(std::initializer_list list, + const allocator_type& alloc = allocator_type()) + : mSize(list.size()), + mCapacityAllocator(list.size(), alloc) { + mData = this->allocator().allocate(this->capacity()); + std::uninitialized_copy(list.begin(), list.end(), begin()); + } + + FixedCapacityVector(size_type size, const_reference value, + const allocator_type& alloc = allocator_type()) + : mSize(size), + mCapacityAllocator(size, alloc) { + mData = this->allocator().allocate(this->capacity()); + construct(begin(), end(), value); + } + + FixedCapacityVector(FixedCapacityVector const& rhs) + : mSize(rhs.mSize), + mCapacityAllocator(rhs.capacity(), + storage_traits::select_on_container_copy_construction(rhs.allocator())) { + mData = allocator().allocate(capacity()); + std::uninitialized_copy(rhs.begin(), rhs.end(), begin()); + } + + FixedCapacityVector(FixedCapacityVector&& rhs) noexcept { + this->swap(rhs); + } + + ~FixedCapacityVector() noexcept { + destroy(begin(), end()); + allocator().deallocate(data(), capacity()); + } + + FixedCapacityVector& operator=(FixedCapacityVector const& rhs) { + if (this != &rhs) { + FixedCapacityVector t(rhs); + this->swap(t); + } + return *this; + } + + FixedCapacityVector& operator=(FixedCapacityVector&& rhs) noexcept { + this->swap(rhs); + return *this; + } + + allocator_type get_allocator() const noexcept { + return mCapacityAllocator.second(); + } + + // -------------------------------------------------------------------------------------------- + + iterator begin() noexcept { return data(); } + iterator end() noexcept { return data() + size(); } + const_iterator begin() const noexcept { return data(); } + const_iterator end() const noexcept { return data() + size(); } + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + const_reverse_iterator crend() const noexcept { return rend(); } + + // -------------------------------------------------------------------------------------------- + + size_type size() const noexcept { return mSize; } + size_type capacity() const noexcept { return mCapacityAllocator.first(); } + bool empty() const noexcept { return size() == 0; } + size_type max_size() const noexcept { + return std::min(storage_traits::max_size(allocator()), + std::numeric_limits::max()); + } + + // -------------------------------------------------------------------------------------------- + + reference operator[](size_type n) noexcept { + assert(n < size()); + return *(begin() + n); + } + + const_reference operator[](size_type n) const noexcept { + assert(n < size()); + return *(begin() + n); + } + + reference front() noexcept { return *begin(); } + const_reference front() const noexcept { return *begin(); } + reference back() noexcept { return *(end() - 1); } + const_reference back() const noexcept { return *(end() - 1); } + value_type* data() noexcept { return mData; } + const value_type* data() const noexcept { return mData; } + + // -------------------------------------------------------------------------------------------- + + void push_back(const_reference v) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, v); + } + + void push_back(value_type&& v) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, std::move(v)); + } + + template + reference emplace_back(ARGS&& ... args) { + auto pos = assertCapacityForSize(size() + 1); + ++mSize; + storage_traits::construct(allocator(), pos, std::forward(args)...); + return *pos; + } + + void pop_back() { + assert(!empty()); + --mSize; + destroy(end(), end() + 1); + } + + iterator insert(const_iterator position, const_reference v) { + if (position == end()) { + push_back(v); + } else { + assertCapacityForSize(size() + 1); + pointer p = const_cast(position); + move_range(p, end(), p + 1); + ++mSize; + // here we handle inserting an element of this vector! + const_pointer pv = std::addressof(v); + if (p <= pv && pv < end()) { + *p = *(pv + 1); + } else { + *p = v; + } + } + return const_cast(position); + } + + iterator insert(const_iterator position, value_type&& v) { + if (position == end()) { + push_back(std::move(v)); + } else { + assertCapacityForSize(size() + 1); + pointer p = const_cast(position); + move_range(p, end(), p + 1); + ++mSize; + *p = std::move(v); + } + return const_cast(position); + } + + iterator erase(const_iterator pos) { + assert(pos != end()); + return erase(pos, pos + 1); + } + + iterator erase(const_iterator first, const_iterator last) { + assert(first <= last); + auto e = std::move(const_cast(last), end(), const_cast(first)); + destroy(e, end()); + mSize -= std::distance(first, last); + return const_cast(first); + } + + void clear() noexcept { + destroy(begin(), end()); + mSize = 0; + } + + void resize(size_type count) { + assertCapacityForSize(count); + if constexpr(std::is_trivially_constructible_v && + std::is_trivially_destructible_v) { + // we check for triviality here so that the implementation could be non-inline + mSize = count; + } else { + resize_non_trivial(count); + } + } + + void resize(size_type count, const_reference v) { + assertCapacityForSize(count); + resize_non_trivial(count, v); + } + + void swap(FixedCapacityVector& other) { + using std::swap; + swap(mData, other.mData); + swap(mSize, other.mSize); + mCapacityAllocator.swap(other.mCapacityAllocator); + } + + UTILS_NOINLINE + void reserve(size_type c) { + if (c > capacity()) { + FixedCapacityVector t(construct_with_capacity, c, allocator()); + t.mSize = size(); + std::uninitialized_move(begin(), end(), t.begin()); + this->swap(t); + } + } + +private: + enum construct_with_capacity_tag{ construct_with_capacity }; + + FixedCapacityVector(construct_with_capacity_tag, + size_type capacity, const allocator_type& allocator = allocator_type()) + : mCapacityAllocator(capacity, allocator) { + mData = this->allocator().allocate(this->capacity()); + } + + allocator_type& allocator() noexcept { + return mCapacityAllocator.second(); + } + + allocator_type const& allocator() const noexcept { + return mCapacityAllocator.second(); + } + + iterator assertCapacityForSize(size_type s) { + if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) { + ASSERT_PRECONDITION(capacity() >= s, + "capacity exceeded: requested size %lu, available capacity %lu.", + (unsigned long)s, (unsigned long)capacity()); + } + return end(); + } + + inline void construct(iterator first, iterator last) noexcept { + // we check for triviality here so that the implementation could be non-inline + if constexpr(!std::is_trivially_constructible_v) { + construct_non_trivial(first, last); + } + } + + void construct(iterator first, iterator last, const_reference proto) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::construct(allocator(), first++, proto); + } + } + + // should this be NOINLINE? + void construct_non_trivial(iterator first, iterator last) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::construct(allocator(), first++); + } + } + + + inline void destroy(iterator first, iterator last) noexcept { + // we check for triviality here so that the implementation could be non-inline + if constexpr(!std::is_trivially_destructible_v) { + destroy_non_trivial(first, last); + } + } + + // should this be NOINLINE? + void destroy_non_trivial(iterator first, iterator last) noexcept { + UTILS_NOUNROLL + while (first != last) { + storage_traits::destroy(allocator(), --last); + } + } + + // should this be NOINLINE? + void resize_non_trivial(size_type count) { + if (count > size()) { + construct(end(), begin() + count); + } else if (count < size()) { + destroy(begin() + count, end()); + } + mSize = count; + } + + // should this be NOINLINE? + void resize_non_trivial(size_type count, const_reference v) { + if (count > size()) { + construct(end(), begin() + count, v); + } else if (count < size()) { + destroy(begin() + count, end()); + } + mSize = count; + } + + // should this be NOINLINE? + void move_range(pointer s, pointer e, pointer to) { + if constexpr(std::is_trivially_copy_assignable_v + && std::is_trivially_destructible_v) { + // this generates memmove -- which doesn't happen otherwise + std::move_backward(s, e, to + std::distance(s, e)); + } else { + pointer our_end = end(); + difference_type n = our_end - to; // nb of elements to move by operator= + pointer i = s + n; // 1st element to move by move ctor + for (pointer d = our_end ; i < our_end ; ++i, ++d) { + storage_traits::construct(allocator(), d, std::move(*i)); + } + std::move_backward(s, s + n, our_end); + } + } + + template + class SizeTypeWrapper { + TYPE value{}; + public: + SizeTypeWrapper() noexcept = default; + SizeTypeWrapper(SizeTypeWrapper const& rhs) noexcept = default; + explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { } + SizeTypeWrapper& operator=(TYPE rhs) noexcept { value = rhs; return *this; } + SizeTypeWrapper& operator=(SizeTypeWrapper& rhs) noexcept = delete; + operator TYPE() const noexcept { return value; } + }; + + pointer mData{}; + size_type mSize{}; + compressed_pair, allocator_type> mCapacityAllocator{}; +}; + +} // namespace utils + +#endif // TNT_UTILS_FIXEDCAPACITYVECTOR_H diff --git a/package/ios/libs/filament/include/utils/Invocable.h b/package/ios/libs/filament/include/utils/Invocable.h new file mode 100644 index 00000000..49b43071 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Invocable.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef TNT_UTILS_INVOKABLE_H +#define TNT_UTILS_INVOKABLE_H + +#include +#include + +#include + +namespace utils { + +/* + * Invocable is a move-only general purpose function wrapper. Instances can + * store and invoke lambda expressions and other function objects. + * + * It is similar to std::function, with the following differences: + * - Invocable is move only. + * - Invocable can capture move only types. + * - No conversion between 'compatible' functions. + * - No small buffer optimization + */ + +// Helper for enabling methods if Fn matches the function signature +// requirements of the Invocable type. +#if __cplusplus >= 201703L +// only available on C++17 and up +template +using EnableIfFnMatchesInvocable = + std::enable_if_t && + std::is_same_v>, int>; +#else +template +using EnableIfFnMatchesInvocable = std::enable_if_t; +#endif + +template +class Invocable; + +template +class Invocable { +public: + // Creates an Invocable that does not contain a functor. + // Will evaluate to false. + Invocable() = default; + + ~Invocable() noexcept; + + // Creates an Invocable from the functor passed in. + template = 0> + Invocable(Fn&& fn) noexcept; // NOLINT(google-explicit-constructor) + + Invocable(const Invocable&) = delete; + Invocable(Invocable&& rhs) noexcept; + + Invocable& operator=(const Invocable&) = delete; + Invocable& operator=(Invocable&& rhs) noexcept; + + // Invokes the invocable with the args passed in. + // If the Invocable is empty, this will assert. + template + R operator()(OperatorArgs&& ... args); + template + R operator()(OperatorArgs&& ... args) const; + + // Evaluates to true if Invocable contains a functor, false otherwise. + explicit operator bool() const noexcept; + +private: + void* mInvocable = nullptr; + void (*mDeleter)(void*) = nullptr; + R (* mInvoker)(void*, Args...) = nullptr; +}; + +template +template> +Invocable::Invocable(Fn&& fn) noexcept + : mInvocable(new Fn(std::forward>(fn))), + mDeleter(+[](void* erased_invocable) { + auto typed_invocable = static_cast(erased_invocable); + delete typed_invocable; + }), + mInvoker(+[](void* erased_invocable, Args... args) -> R { + auto typed_invocable = static_cast(erased_invocable); + return (*typed_invocable)(std::forward(args)...); + }) +{ +} + +template +Invocable::~Invocable() noexcept { + if (mDeleter) { + mDeleter(mInvocable); + } +} + +template +Invocable::Invocable(Invocable&& rhs) noexcept + : mInvocable(rhs.mInvocable), + mDeleter(rhs.mDeleter), + mInvoker(rhs.mInvoker) { + rhs.mInvocable = nullptr; + rhs.mDeleter = nullptr; + rhs.mInvoker = nullptr; +} + +template +Invocable& Invocable::operator=(Invocable&& rhs) noexcept { + if (this != &rhs) { + std::swap(mInvocable, rhs.mInvocable); + std::swap(mDeleter, rhs.mDeleter); + std::swap(mInvoker, rhs.mInvoker); + } + return *this; +} + +template +template +R Invocable::operator()(OperatorArgs&& ... args) { + assert(mInvoker && mInvocable); + return mInvoker(mInvocable, std::forward(args)...); +} + +template +template +R Invocable::operator()(OperatorArgs&& ... args) const { + assert(mInvoker && mInvocable); + return mInvoker(mInvocable, std::forward(args)...); +} + +template +Invocable::operator bool() const noexcept { + return mInvoker != nullptr && mInvocable != nullptr; +} + +} // namespace utils + +#endif // TNT_UTILS_INVOKABLE_H diff --git a/package/ios/libs/filament/include/utils/Log.h b/package/ios/libs/filament/include/utils/Log.h new file mode 100644 index 00000000..77886426 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Log.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_LOG_H +#define TNT_UTILS_LOG_H + +#include +#include + +namespace utils { + +struct UTILS_PUBLIC Loggers { + // DEBUG level logging stream + io::ostream& d; + + // ERROR level logging stream + io::ostream& e; + + // WARNING level logging stream + io::ostream& w; + + // INFORMATION level logging stream + io::ostream& i; + + // VERBOSE level logging stream + io::ostream& v; +}; + +extern UTILS_PUBLIC Loggers const slog; + +} // namespace utils + +#endif // TNT_UTILS_LOG_H diff --git a/package/ios/libs/filament/include/utils/Mutex.h b/package/ios/libs/filament/include/utils/Mutex.h new file mode 100644 index 00000000..1de6257f --- /dev/null +++ b/package/ios/libs/filament/include/utils/Mutex.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_UTILS_MUTEX_H +#define TNT_UTILS_MUTEX_H + +#if defined(__ANDROID__) +#include +#else +#include +#endif + +#endif // TNT_UTILS_MUTEX_H diff --git a/package/ios/libs/filament/include/utils/NameComponentManager.h b/package/ios/libs/filament/include/utils/NameComponentManager.h new file mode 100644 index 00000000..4ac7435a --- /dev/null +++ b/package/ios/libs/filament/include/utils/NameComponentManager.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H +#define TNT_UTILS_NAMECOMPONENTMANAGER_H + +#include +#include +#include +#include +#include + +#include + +namespace utils { + +class EntityManager; + +/** + * \class NameComponentManager NameComponentManager.h utils/NameComponentManager.h + * \brief Allows clients to associate string labels with entities. + * + * To access the name of an existing entity, clients should first use NameComponentManager to get a + * temporary handle called an \em instance. Please note that instances are ephemeral; clients should + * store entities, not instances. + * + * Usage example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * auto names = new NameComponentManager(EntityManager::get()); + * names->addComponent(myEntity); + * names->setName(names->getInstance(myEntity), "Jeanne d'Arc"); + * ... + * printf("%s\n", names->getName(names->getInstance(myEntity)); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +class UTILS_PUBLIC NameComponentManager : private SingleInstanceComponentManager { +public: + using Instance = EntityInstance; + + /** + * Creates a new name manager associated with the given entity manager. + * + * Note that multiple string labels could be associated with each entity simply by + * creating multiple instances of NameComponentManager. + */ + explicit NameComponentManager(EntityManager& em); + ~NameComponentManager(); + + /** + * Checks if the given entity already has a name component. + */ + using SingleInstanceComponentManager::hasComponent; + + /** + * Gets a temporary handle that can be used to access the name. + * + * @return Non-zero handle if the entity has a name component, 0 otherwise. + */ + Instance getInstance(Entity e) const noexcept { + return { SingleInstanceComponentManager::getInstance(e) }; + } + + /** + * Adds a name component to the given entity if it doesn't already exist. + */ + void addComponent(Entity e); + + /** + * Removes the name component to the given entity if it exists. + */ + void removeComponent(Entity e); + + /** + * Stores a copy of the given string and associates it with the given instance. + */ + void setName(Instance instance, const char* name) noexcept; + + /** + * Retrieves the string associated with the given instance, or nullptr if none exists. + * + * @return pointer to the copy that was made during setName() + */ + const char* getName(Instance instance) const noexcept; + + void gc(EntityManager& em) noexcept { + SingleInstanceComponentManager::gc(em, [this](Entity e) { + removeComponent(e); + }); + } +}; + +} // namespace utils + +#endif // TNT_UTILS_NAMECOMPONENTMANAGER_H diff --git a/package/ios/libs/filament/include/utils/Panic.h b/package/ios/libs/filament/include/utils/Panic.h new file mode 100644 index 00000000..b4ec032c --- /dev/null +++ b/package/ios/libs/filament/include/utils/Panic.h @@ -0,0 +1,563 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_PANIC_H +#define TNT_UTILS_PANIC_H + +#include +#include + +#include + +#ifdef __EXCEPTIONS +# define UTILS_EXCEPTIONS 1 +#else +#endif + +/** + * @defgroup errors Handling Catastrophic Failures (Panics) + * + * @brief Failure detection and reporting facilities + * + * ## What's a Panic? ## + * + * In the context of this document, a _panic_ is a type of error due to a _contract violation_, + * it shouldn't be confused with a _result_ or _status_ code. The POSIX API for instance, + * unfortunately often conflates the two. + * @see + * + * + * Here we give the following definition of a _panic_: + * + * 1. Failures to meet a function's own **postconditions**\n + * The function cannot establish one of its own postconditions, such as (but not limited to) + * producing a valid return value object. + * + * Often these failures are only detectable at runtime, for instance they can be caused by + * arithmetic errors, as it was the case for the Ariane 5 rocket. Ariane 5 crashed because it + * reused an inertial module from Ariane 4, which didn't account for the greater horizontal + * acceleration of Ariane 5 and caused an overflow in the computations. Ariane 4's module + * wasn't per-say buggy, but was improperly used and failed to meet, obviously, certain + * postconditions. + * @see + * + * 2. Failures to meet the **preconditions** of any of a function's callees\n + * The function cannot meet a precondition of another function it must call, such as a + * restriction on a parameter. + * + * Not to be confused with the case where the preconditions of a function are already + * violated upon entry, which indicates a programming error from the caller. + * + * Typically these failures can be avoided and arise because of programming errors. + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Failure reporting vs. handling ## + * + * Very often when a panic, as defined above, is detected, the program has little other choice + * but to terminate.\n + * Typically these situations can be handled by _assert()_. However, _assert()_ also conflates two + * very different concepts: detecting and handling failures.\n + * The place where a failure is detected is rarely the place where there is enough + * context to decide what to do. _assert()_ terminates the program which, may or may not be + * appropriate. At the very least the failure must be logged (which _assert()_ does in a crude way), + * but some other actions might need to happen, such as:\n + * + * - logging the failure in the system-wide logger + * - providing enough information in development builds to analyze/debug the problem + * - cleanly releasing some resources, such as communication channels with other processes\n + * e.g.: to avoid their pre- or postconditions from being violated as well. + * + * In some _rare_ cases, the failure might even be ignored altogether because it doesn't matter in + * the context where it happened. This decision clearly doesn't always lie at the failure-site. + * + * It is therefore important to separate failure detection from handling. + * + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Failure detection and handling facilities ## + * + * Clearly, catastrophic failures should be **rare**; in fact they should + * never happen, except possibly for "failures to meet a function's own postconditions", which + * may depend on external factors and should still be very rare. Yet, when a failure happens, it + * must be detected and handled appropriately.\n + * Since panics are rare, it is desirable that the handling mechanism be as unobtrusive + * as possible, without allowing such failures to go unnoticed or swallowed by mistake. Ideally, the + * programmer using an API should have nothing special to do to handle that API's failure + * conditions.\n\n + * + * An important feature of the Panic Handling facilities here is that **panics are not part of + * the API of a function or method**\n\n + * + * + * The panic handling facility has the following benefits: + * - provides an easy way to detect and report failure + * - separates failure detection from handling + * - makes it hard for detected failures to be ignored (i.e.: not handled) + * - doesn't add burden on the API design + * - doesn't add overhead (visual or otherwise) at call sites + * - has very little performance overhead for failure detection + * - has little to no performance impact for failure handling in the common (success) case + * - is flexible and extensible + * + * Since we have established that failures are **rare**, **exceptional** situations, it would be + * appropriate to handle them with an _assert_ mechanism and that's what the API below + * provides. However, under-the-hood it uses C++ exceptions as a means to separate + * _reporting_ from _handling_. + * + * \note On devices where exceptions are not supported or appropriate, these APIs can be turned + * into a regular _std::terminate()_. + * + * + * ASSERT_PRECONDITION(condition, format, ...) + * ASSERT_POSTCONDITION(condition, format, ...) + * ASSERT_ARITHMETIC(condition, format, ...) + * ASSERT_DESTRUCTOR(condition, format, ...) + * + * + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see ASSERT_DESTRUCTOR + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ## Writing code that can assert ## + * + * Because we've separated failure reporting from failure handling, there are some considerations + * that need to be thought about when writing code that calls the macros above (i.e.: the program + * won't terminate at the point where the failure is detected).\n\n + * + * + * ### Panic guarantees ### + * + * After the failure condition is reported by a function, additional guarantees may be provided + * with regards to the state of the program. The following four levels of guarantee are + * generally recognized, each of which is a strict superset of its successors: + * + * 1. Nothrow exception guarantee\n + * The function never asserts. e.g.: This should always be the case with destructors.\n\n + * + * 2. Strong exception guarantee\n + * If the function asserts, the state of the program is rolled back to the state just before + * the function call.\n\n + * + * 3. Basic exception guarantee\n + * If the function asserts, the program is in a valid state. It may require cleanup, + * but all invariants are intact.\n\n + * + * 4. No exception guarantee\n + * If the function asserts, the program may not be in a valid state: resource leaks, memory + * corruption, or other invariant-destroying failures may have occurred. + * + * In each function, give the **strongest** safety guarantee that won't penalize callers who + * don't need it, but **always give at least the basic guarantee**. The RAII (Resource + * Acquisition Is Initialization) pattern can help with achieving these guarantees. + * + * @see [RAII](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) + * + * ### Special considerations for Constructors ### + * + * Constructors are a bit special because if a failure occurs during their execution, the + * destructor won't be called (how could it? since the object wasn't constructed!). This can lead + * to leaked resources allocated in the constructor prior to the failure. Thankfully there is + * a nice C++ syntax to handle this case: + * + * @code + * Foo::Foo(size_t s) try : m_size(s), m_buf(new uint32_t[s]) { + * ASSERT_POSTCONDITION(s&0xF==0, + * "object size is %u, but must be multiple of 16", s); + * } catch (...) { + * delete [] m_buf; + * // the exception will be automatically re-thrown + * } + * @endcode + * + * Unfortunately, this usage leaks the underlying, exception-based, implementation of the + * panic handling macros. For this reason, it is best to keep constructors simple and guarantee + * they can't fail. An _init()_ function with a factory can be used for actual initialization. + * + * + * ### Special considerations for Destructors ### + * + * In C++ destructors cannot throw exceptions and since the above macros internally use exceptions + * they cannot be used in destructors. Doing so will result in immediate termination of the + * program by _std::terminate()_.\n + * It is therefore best to always guarantee that destructors won't fail. In case of such a + * failure in a destructor the ASSERT_DESTRUCTOR() macro can be used instead, it + * will log the failure but won't terminate the program, instead it'll proceed as if nothing + * happened. Generally this will result in some resource leak which, eventually, will cause + * another failure (typically a postcondition violation).\n\n + * + * Rationale for this behavior: There are fundamentally no way to report a failure from a + * destructor in C++, violently terminating the process is inadequate because it again conflates + * failure reporting and failure handling; for instance a failure in glDeleteTextures() shouldn't + * be necessarily fatal (certainly not without saving the user's data first). The alternative + * would be for the caller to swallow the failure entirely, but that's not great either because the + * failure would go unnoticed. The solution retained here is a compromise. + * + * @see ASSERT_DESTRUCTOR + * + * ### Testing Code that Uses Panics ### + * + * Since panics use exceptions for their underlying implementation, you can test code that uses + * panics with EXPECT_THROW by doing the following things: + * \li Set panic mode to THROW (default is TERMINATE) + * \li Pass Panic to EXPECT_THROW as the exception type + * + * Example code for your test file: + * + * @code + * #include // since your code uses panics, this should include utils/Panic.hpp + * + * using utils::Panic; + * + * TEST(MyClassTest, value_that_causes_panic) { + * EXPECT_THROW(MyClass::function(value_that_causes_panic), Panic); + * } + * + * // ... other tests ... + * + * int main(int argc, char** argv) { + * ::testing::InitGoogleTest(&argc, argv); + * Panic::setMode(Panic::Mode::THROW); + * return RUN_ALL_TESTS(); + * } + * @endcode + * + */ + +namespace utils { + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * \brief Base class of all exceptions thrown by all the ASSERT macros + * + * The Panic class provides the std::exception protocol, it is the base exception object + * used for all thrown exceptions. + */ +class UTILS_PUBLIC Panic { +public: + virtual ~Panic() noexcept; + + /** + * @return a detailed description of the error + * @see std::exception + */ + virtual const char* what() const noexcept = 0; + + /** + * Get the function name where the panic was detected + * @return a C string containing the function name where the panic was detected + */ + virtual const char* getFunction() const noexcept = 0; + + /** + * Get the file name where the panic was detected + * @return a C string containing the file name where the panic was detected + */ + virtual const char* getFile() const noexcept = 0; + + /** + * Get the line number in the file where the panic was detected + * @return an integer containing the line number in the file where the panic was detected + */ + virtual int getLine() const noexcept = 0; + + /** + * Logs this exception to the system-log + */ + virtual void log() const noexcept = 0; + + /** + * Get the CallStack when the panic was detected + * @return the CallStack when the panic was detected + */ + virtual const CallStack& getCallStack() const noexcept = 0; +}; + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * \brief Concrete implementation of the Panic interface. + * + * The TPanic<> class implements the std::exception protocol as well as the Panic + * interface common to all exceptions thrown by the framework. + */ +template +class UTILS_PUBLIC TPanic : public Panic { +public: + // std::exception protocol + const char* what() const noexcept override; + + // Panic interface + const char* getFunction() const noexcept override; + const char* getFile() const noexcept override; + int getLine() const noexcept override; + const CallStack& getCallStack() const noexcept override; + void log() const noexcept override; + + /** + * Depending on the mode set, either throws an exception of type T with the given reason plus + * extra information about the error-site, or logs the error and calls std::terminate(). + * This function never returns. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param format printf style string describing the error + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC + * @see setMode() + */ + static void panic(char const* function, char const* file, int line, const char* format, ...) + UTILS_NORETURN; + + /** + * Depending on the mode set, either throws an exception of type T with the given reason plus + * extra information about the error-site, or logs the error and calls std::terminate(). + * This function never returns. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param s std::string describing the error + * @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC + * @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC + * @see setMode() + */ + static inline void panic(char const* function, char const* file, int line, const std::string& s) + UTILS_NORETURN { + panic(function, file, line, s.c_str()); + } + +protected: + /** + * Creates a Panic. + * @param reason a description of the cause of the error + */ + explicit TPanic(std::string reason); + + /** + * Creates a Panic with extra information about the error-site. + * @param function the name of the function where the error was detected + * @param file the file where the above function in implemented + * @param line the line in the above file where the error was detected + * @param reason a description of the cause of the error + */ + TPanic(char const* function, char const* file, int line, std::string reason); + + ~TPanic() override; + +private: + void buildMessage(); + + CallStack m_callstack; + std::string m_reason; + char const* const m_function = nullptr; + char const* const m_file = nullptr; + const int m_line = -1; + mutable std::string m_msg; +}; + +namespace details { +// these are private, don't use +void panicLog( + char const* function, char const* file, int line, const char* format, ...) noexcept; +} // namespace details + +// ----------------------------------------------------------------------------------------------- + +/** + * @ingroup errors + * + * ASSERT_PRECONDITION uses this Panic to report a precondition failure. + * @see ASSERT_PRECONDITION + */ +class UTILS_PUBLIC PreconditionPanic : public TPanic { + // Programming error, can be avoided + // e.g.: invalid arguments + using TPanic::TPanic; + friend class TPanic; +}; + +/** + * @ingroup errors + * + * ASSERT_POSTCONDITION uses this Panic to report a postcondition failure. + * @see ASSERT_POSTCONDITION + */ +class UTILS_PUBLIC PostconditionPanic : public TPanic { + // Usually only detectable at runtime + // e.g.: dead-lock would occur, arithmetic errors + using TPanic::TPanic; + friend class TPanic; +}; + +/** + * @ingroup errors + * + * ASSERT_ARITHMETIC uses this Panic to report an arithmetic (postcondition) failure. + * @see ASSERT_ARITHMETIC + */ +class UTILS_PUBLIC ArithmeticPanic : public TPanic { + // A common case of post-condition error + // e.g.: underflow, overflow, internal computations errors + using TPanic::TPanic; + friend class TPanic; +}; + +// ----------------------------------------------------------------------------------------------- +} // namespace utils + +#ifndef NDEBUG +# define PANIC_FILE(F) (F) +# define PANIC_FUNCTION __PRETTY_FUNCTION__ +#else +# define PANIC_FILE(F) "" +# define PANIC_FUNCTION __func__ +#endif + +/** + * PANIC_PRECONDITION is a macro that reports a PreconditionPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_PRECONDITION(format, ...) \ + ::utils::PreconditionPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_POSTCONDITION is a macro that reports a PostconditionPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_POSTCONDITION(format, ...) \ + ::utils::PostconditionPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_ARITHMETIC is a macro that reports a ArithmeticPanic + * @param format printf-style string describing the error in more details + */ +#define PANIC_ARITHMETIC(format, ...) \ + ::utils::ArithmeticPanic::panic(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * PANIC_LOG is a macro that logs a Panic, and continues as usual. + * @param format printf-style string describing the error in more details + */ +#define PANIC_LOG(format, ...) \ + ::utils::details::panicLog(PANIC_FUNCTION, \ + PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__) + +/** + * @ingroup errors + * + * ASSERT_PRECONDITION is a macro that checks the given condition and reports a PreconditionPanic + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + */ +#define ASSERT_PRECONDITION(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__) : (void)0) + +#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG) +#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_PRECONDITION(format, ##__VA_ARGS__), false : true) +#else +#define ASSERT_PRECONDITION_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true) +#endif + + +/** + * @ingroup errors + * + * ASSERT_POSTCONDITION is a macro that checks the given condition and reports a PostconditionPanic + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + * + * Example: + * @code + * int& Foo::operator[](size_t index) { + * ASSERT_POSTCONDITION(index=0 && v<65536, "overflow occurred"); + * return uint32_t(v); + * } + * @endcode + */ +#define ASSERT_ARITHMETIC(cond, format, ...) \ + (!(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__) : (void)0) + +#if defined(UTILS_EXCEPTIONS) || !defined(NDEBUG) +#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_ARITHMETIC(format, ##__VA_ARGS__), false : true) +#else +#define ASSERT_ARITHMETIC_NON_FATAL(cond, format, ...) \ + (!UTILS_LIKELY(cond) ? PANIC_LOG(format, ##__VA_ARGS__), false : true) +#endif + +/** + * @ingroup errors + * + * ASSERT_DESTRUCTOR is a macro that checks the given condition and logs an error + * if it evaluates to false. + * @param cond a boolean expression + * @param format printf-style string describing the error in more details + * + * @warning Use this macro if a destructor can fail, which should be avoided at all costs. + * Unlike the other ASSERT macros, this will never result in the process termination. Instead, + * the error will be logged and the program will continue as if nothing happened. + * + * Example: + * @code + * Foo::~Foo() { + * glDeleteTextures(1, &m_texture); + * GLint err = glGetError(); + * ASSERT_DESTRUCTOR(err == GL_NO_ERROR, "cannot free GL resource!"); + * } + * @endcode + */ +#define ASSERT_DESTRUCTOR(cond, format, ...) (!(cond) ? PANIC_LOG(format, ##__VA_ARGS__) : (void)0) + +#endif // TNT_UTILS_PANIC_H diff --git a/package/ios/libs/filament/include/utils/Path.h b/package/ios/libs/filament/include/utils/Path.h new file mode 100644 index 00000000..48195b26 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Path.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_PATH_H +#define TNT_UTILS_PATH_H + +#include + +#include +#include +#include + +namespace utils { + +/** + * An abstract representation of file and directory paths. + */ +class UTILS_PUBLIC Path { +public: + /** + * Creates a new empty path. + */ + Path() = default; + ~Path() = default; + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a non-null pathname string + */ + Path(const char* pathname); + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a pathname string view + */ + Path(std::string_view pathname); + + /** + * Creates a new path with the specified pathname. + * + * @param pathname a pathname string + */ + Path(const std::string& pathname); + + /** + * Tests whether the file or directory denoted by this abstract + * pathname exists. + * + * @return true if the file or directory denoted by this + * abstract pathname exists, false otherwise + */ + bool exists() const; + + /** + * Tests whether this abstract pathname represents a regular file. + * This method can only return true if the path exists. + * + * @return true if this pathname represents an existing file, + * false if the path doesn't exist or represents something + * else (directory, symlink, etc.) + */ + bool isFile() const; + + /** + * Tests whether this abstract pathname represents a directory. + * This method can only return true if the path exists. + * + * @return true if this pathname represents an existing directory, + * false if the path doesn't exist or represents a file + */ + bool isDirectory() const; + + /** + * Tests whether this path is empty. An empty path does not + * exist. + * + * @return true if the underlying abstract pathname is empty, + * false otherwise + */ + bool isEmpty() const { return m_path.empty(); } + + const char* c_str() const { return m_path.c_str(); } + + /** + * Replaces the abstract pathname of this object with the + * specified pathname. + * + * @param pathname a pathname string + */ + void setPath(const std::string& pathname) { + m_path = getCanonicalPath(pathname); + } + + /** + * @return the canonical pathname this path represents + */ + const std::string& getPath() const { return m_path; } + + /** + * Returns the parent of this path as Path. + * @return a new path containing the parent of this path + */ + Path getParent() const; + + /** + * Returns ancestor path where "0" is the immediate parent. + * @return a new path containing the ancestor of this path + */ + Path getAncestor(int n) const; + + /** + * Returns the name of the file or directory represented by + * this abstract pathname. + * + * @return the name of the file or directory represented by + * this abstract pathname, or an empty string if + * this path is empty + */ + std::string getName() const; + + /** + * Returns the name of the file or directory represented by + * this abstract pathname without its extension. + * + * @return the name of the file or directory represented by + * this abstract pathname, or an empty string if + * this path is empty + */ + std::string getNameWithoutExtension() const; + + /** + * Returns the file extension (after the ".") if one is present. + * Returns the empty string if no filename is present or if the + * path is a directory. + * + * @return the file extension (if one is present and + * this is not a directory), else the empty string. + */ + std::string getExtension() const; + + /** + * Returns the absolute representation of this path. + * If this path's pathname starts with a leading '/', + * the returned path is equal to this path. Otherwise, + * this path's pathname is concatenated with the current + * working directory and the result is returned. + * + * @return a new path containing the absolute representation + * of this path + */ + Path getAbsolutePath() const; + + /** + * @return true if this abstract pathname is not empty + * and starts with a leading '/', false otherwise + */ + bool isAbsolute() const; + + /** + * Splits this object's abstract pathname in a vector of file + * and directory name. If the underlying abstract pathname + * starts with a '/', the returned vector's first element + * will be the string "/". + * + * @return a vector of strings, empty if this path is empty + */ + std::vector split() const; + + /** + * Concatenates the specified path with this path in a new + * path object. + * + * @note if the pathname to concatenate with starts with + * a leading '/' then that pathname is returned without + * being concatenated to this object's pathname. + * + * @param path the path to concatenate with + * + * @return the concatenation of the two paths + */ + Path concat(const Path& path) const; + + /** + * Concatenates the specified path with this path and + * stores the result in this path. + * + * @note if the pathname to concatenate with starts with + * a leading '/' then that pathname replaces this object's + * pathname. + * + * @param path the path to concatenate with + */ + void concatToSelf(const Path& path); + + operator std::string const&() const { return m_path; } + + Path operator+(const Path& rhs) const { return concat(rhs); } + Path& operator+=(const Path& rhs) { + concatToSelf(rhs); + return *this; + } + + bool operator==(const Path& rhs) const { return m_path == rhs.m_path; } + bool operator!=(const Path& rhs) const { return m_path != rhs.m_path; } + + bool operator<(const Path& rhs) const { return m_path < rhs.m_path; } + bool operator>(const Path& rhs) const { return m_path > rhs.m_path; } + + friend std::ostream& operator<<(std::ostream& os, const Path& path); + + /** + * Returns a canonical copy of the specified pathname by removing + * unnecessary path segments such as ".", ".." and "/". + * + * @param pathname a pathname string + * + * @return the canonical representation of the specified pathname + */ + static std::string getCanonicalPath(const std::string& pathname); + + /** + * This method is equivalent to calling root.concat(leaf). + */ + static Path concat(const std::string& root, const std::string& leaf); + + /** + * @return a path representing the current working directory + */ + static Path getCurrentDirectory(); + + /** + * @return a path representing the current executable + */ + static Path getCurrentExecutable(); + + /** + * @return a path representing a directory where temporary files can be stored + */ + static Path getTemporaryDirectory(); + + /** + * @return a path representing a directory where settings files can be stored, + * it is recommended to append an app specific folder name to that path + */ + static Path getUserSettingsDirectory(); + + /** + * Creates a directory denoted by the given path. + * This is not recursive and doesn't create intermediate directories. + * + * @return True if directory was successfully created. + * When false, errno should have details on actual error. + */ + bool mkdir() const; + + /** + * Creates a directory denoted by the given path. + * This is recursive and parent directories will be created if they do not + * exist. + * + * @return True if directory was successfully created or already exists. + * When false, errno should have details on actual error. + */ + bool mkdirRecursive() const; + + /** + * Deletes this file. + * + * @return True if file was successfully deleted. + * When false, errno should have details on actual error. + */ + bool unlinkFile(); + + /** + * Lists the contents of this directory, skipping hidden files. + * + * @return A vector of paths of the contents of the directory. If the path points to a file, + * nonexistent directory, or empty directory, an empty vector is returned. + */ + std::vector listContents() const; + +private: + std::string m_path; +}; + +} // namespace utils + +#endif // TNT_UTILS_PATH_H diff --git a/package/ios/libs/filament/include/utils/PrivateImplementation-impl.h b/package/ios/libs/filament/include/utils/PrivateImplementation-impl.h new file mode 100644 index 00000000..3488b5ae --- /dev/null +++ b/package/ios/libs/filament/include/utils/PrivateImplementation-impl.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef UTILS_PRIVATEIMPLEMENTATION_IMPL_H +#define UTILS_PRIVATEIMPLEMENTATION_IMPL_H + +/* + * This looks like a header file, but really it acts as a .cpp, because it's used to + * explicitly instantiate the methods of PrivateImplementation<> + */ + +#include + +#include + +namespace utils { + +template +PrivateImplementation::PrivateImplementation() noexcept + : mImpl(new T) { +} + +template +template +PrivateImplementation::PrivateImplementation(ARGS&& ... args) noexcept + : mImpl(new T(std::forward(args)...)) { +} + +template +PrivateImplementation::~PrivateImplementation() noexcept { + delete mImpl; +} + +#ifndef UTILS_PRIVATE_IMPLEMENTATION_NON_COPYABLE + +template +PrivateImplementation::PrivateImplementation(PrivateImplementation const& rhs) noexcept + : mImpl(new T(*rhs.mImpl)) { +} + +template +PrivateImplementation& PrivateImplementation::operator=(PrivateImplementation const& rhs) noexcept { + if (this != &rhs) { + *mImpl = *rhs.mImpl; + } + return *this; +} + +#endif + +} // namespace utils + +#endif // UTILS_PRIVATEIMPLEMENTATION_IMPL_H diff --git a/package/ios/libs/filament/include/utils/PrivateImplementation.h b/package/ios/libs/filament/include/utils/PrivateImplementation.h new file mode 100644 index 00000000..ee0ac48a --- /dev/null +++ b/package/ios/libs/filament/include/utils/PrivateImplementation.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef UTILS_PRIVATEIMPLEMENTATION_H +#define UTILS_PRIVATEIMPLEMENTATION_H + +#include + +namespace utils { + +/** + * \privatesection + * PrivateImplementation is used to hide the implementation details of a class and ensure a higher + * level of backward binary compatibility. + * The actual implementation is in src/PrivateImplementation-impl.h" + */ +template +class PrivateImplementation { +public: + // none of these methods must be implemented inline because it's important that their + // implementation be hidden from the public headers. + template + explicit PrivateImplementation(ARGS&& ...) noexcept; + PrivateImplementation() noexcept; + ~PrivateImplementation() noexcept; + PrivateImplementation(PrivateImplementation const& rhs) noexcept; + PrivateImplementation& operator = (PrivateImplementation const& rhs) noexcept; + + // move ctor and copy operator can be implemented inline and don't need to be exported + PrivateImplementation(PrivateImplementation&& rhs) noexcept : mImpl(rhs.mImpl) { rhs.mImpl = nullptr; } + PrivateImplementation& operator = (PrivateImplementation&& rhs) noexcept { + auto temp = mImpl; + mImpl = rhs.mImpl; + rhs.mImpl = temp; + return *this; + } + +protected: + T* mImpl = nullptr; + inline T* operator->() noexcept { return mImpl; } + inline T const* operator->() const noexcept { return mImpl; } +}; + +} // namespace utils + +#endif // UTILS_PRIVATEIMPLEMENTATION_H diff --git a/package/ios/libs/filament/include/utils/SingleInstanceComponentManager.h b/package/ios/libs/filament/include/utils/SingleInstanceComponentManager.h new file mode 100644 index 00000000..ddd538f5 --- /dev/null +++ b/package/ios/libs/filament/include/utils/SingleInstanceComponentManager.h @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H +#define TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace utils { + +class EntityManager; + +/* + * Helper class to create single instance component managers. + * + * This handles the component's storage as a structure-of-arrays, as well + * as the garbage collection. + * + * This is intended to be used as base class for a real component manager. When doing so, + * and the real component manager is a public API, make sure to forward the public methods + * to the implementation. + * + */ +template +class UTILS_PUBLIC SingleInstanceComponentManager { +private: + + // this is just to avoid using std::default_random_engine, since we're in a public header. + class default_random_engine { + uint32_t mState = 1u; // must be 0 < seed < 0x7fffffff + public: + inline uint32_t operator()() noexcept { + return mState = uint32_t((uint64_t(mState) * 48271u) % 0x7fffffffu); + } + }; + +protected: + static constexpr size_t ENTITY_INDEX = sizeof ... (Elements); + + +public: + using SoA = StructureOfArrays; + + using Structure = typename SoA::Structure; + + using Instance = EntityInstanceBase::Type; + + SingleInstanceComponentManager() noexcept { + // We always start with a dummy entry because index=0 is reserved. The component + // at index = 0, is guaranteed to be default-initialized. + // Sub-classes can use this to their advantage. + mData.push_back(Structure{}); + } + + SingleInstanceComponentManager(SingleInstanceComponentManager&&) noexcept {/* = default */} + SingleInstanceComponentManager& operator=(SingleInstanceComponentManager&&) noexcept {/* = default */} + ~SingleInstanceComponentManager() noexcept = default; + + // not copyable + SingleInstanceComponentManager(SingleInstanceComponentManager const& rhs) = delete; + SingleInstanceComponentManager& operator=(SingleInstanceComponentManager const& rhs) = delete; + + + // returns true if the given Entity has a component of this Manager + bool hasComponent(Entity e) const noexcept { + return getInstance(e) != 0; + } + + // Get instance of this Entity to be used to retrieve components + UTILS_NOINLINE + Instance getInstance(Entity e) const noexcept { + auto const& map = mInstanceMap; + // find() generates quite a bit of code + auto pos = map.find(e); + return pos != map.end() ? pos->second : 0; + } + + // Returns the number of components (i.e. size of each array) + size_t getComponentCount() const noexcept { + // The array as an extra dummy component at index 0, so the visible count is 1 less. + return mData.size() - 1; + } + + bool empty() const noexcept { + return getComponentCount() == 0; + } + + utils::Entity const* getEntities() const noexcept { + return data() + 1; + } + + Entity getEntity(Instance i) const noexcept { + return elementAt(i); + } + + // Add a component to the given Entity. If the entity already has a component from this + // manager, this function is a no-op. + // This invalidates all pointers components. + inline Instance addComponent(Entity e); + + // Removes a component from the given entity. + // This invalidates all pointers components. + inline Instance removeComponent(Entity e); + + // return the first instance + Instance begin() const noexcept { return 1u; } + + // return the past-the-last instance + Instance end() const noexcept { return Instance(begin() + getComponentCount()); } + + // return a pointer to the first element of the ElementIndex'th array + template + typename SoA::template TypeAt* begin() noexcept { + return mData.template data() + 1; + } + + template + typename SoA::template TypeAt const* begin() const noexcept { + return mData.template data() + 1; + } + + // return a pointer to the past-the-end element of the ElementIndex'th array + template + typename SoA::template TypeAt* end() noexcept { + return begin() + getComponentCount(); + } + + template + typename SoA::template TypeAt const* end() const noexcept { + return begin() + getComponentCount(); + } + + // return a Slice<> + template + Slice> slice() noexcept { + return { begin(), end() }; + } + + template + Slice> slice() const noexcept { + return { begin(), end() }; + } + + // return a reference to the index'th element of the ElementIndex'th array + template + typename SoA::template TypeAt& elementAt(Instance index) noexcept { + assert(index); + return data()[index]; + } + + template + typename SoA::template TypeAt const& elementAt(Instance index) const noexcept { + assert(index); + return data()[index]; + } + + // returns a pointer to the RAW ARRAY of components including the first dummy component + // Use with caution. + template + typename SoA::template TypeAt const* raw_array() const noexcept { + return data(); + } + + // We need our own version of Field because mData is private + template + struct Field : public SoA::template Field { + Field(SingleInstanceComponentManager& soa, EntityInstanceBase::Type i) noexcept + : SoA::template Field{ soa.mData, i } { + } + using SoA::template Field::operator =; + }; + +protected: + template + typename SoA::template TypeAt* data() noexcept { + return mData.template data(); + } + + template + typename SoA::template TypeAt const* data() const noexcept { + return mData.template data(); + } + + // swap only internals + void swap(Instance i, Instance j) noexcept { + assert(i); + assert(j); + if (i && j) { + // update the index map + auto& map = mInstanceMap; + Entity& ei = elementAt(i); + Entity& ej = elementAt(j); + std::swap(ei, ej); + if (ei) { + map[ei] = i; + } + if (ej) { + map[ej] = j; + } + } + } + + template + void gc(const EntityManager& em, + REMOVE&& removeComponent) noexcept { + gc(em, 4, std::forward(removeComponent)); + } + + template + void gc(const EntityManager& em, size_t ratio, + REMOVE&& removeComponent) noexcept { + Entity const* const pEntities = begin(); + size_t count = getComponentCount(); + size_t aliveInARow = 0; + default_random_engine& rng = mRng; + UTILS_NOUNROLL + while (count && aliveInARow < ratio) { + assert_invariant(count == getComponentCount()); + // note: using the modulo favorizes lower number + size_t const i = rng() % count; + Entity const entity = pEntities[i]; + assert_invariant(entity); + if (UTILS_LIKELY(em.isAlive(entity))) { + ++aliveInARow; + continue; + } + removeComponent(entity); + aliveInARow = 0; + count--; + } + } + +protected: + SoA mData; + +private: + // maps an entity to an instance index + tsl::robin_map mInstanceMap; + default_random_engine mRng; +}; + +// Keep these outside of the class because CLion has trouble parsing them +template +typename SingleInstanceComponentManager::Instance +SingleInstanceComponentManager::addComponent(Entity e) { + Instance ci = 0; + if (!e.isNull()) { + if (!hasComponent(e)) { + // this is like a push_back(e); + mData.push_back(Structure{}).template back() = e; + // index 0 is used when the component doesn't exist + ci = Instance(mData.size() - 1); + mInstanceMap[e] = ci; + } else { + // if the entity already has this component, just return its instance + ci = mInstanceMap[e]; + } + } + assert(ci != 0); + return ci; +} + +// Keep these outside of the class because CLion has trouble parsing them +template +typename SingleInstanceComponentManager::Instance +SingleInstanceComponentManager::removeComponent(Entity e) { + auto& map = mInstanceMap; + auto pos = map.find(e); + if (UTILS_LIKELY(pos != map.end())) { + size_t index = pos->second; + assert(index != 0); + size_t last = mData.size() - 1; + if (last != index) { + // move the last item to where we removed this component, as to keep + // the array tightly packed. + mData.forEach([index, last](auto* p) { + p[index] = std::move(p[last]); + }); + + Entity lastEntity = mData.template elementAt(index); + map[lastEntity] = index; + } + mData.pop_back(); + map.erase(pos); + return last; + } + return 0; +} + + +} // namespace filament + +#endif // TNT_UTILS_SINGLEINSTANCECOMPONENTMANAGER_H diff --git a/package/ios/libs/filament/include/utils/Slice.h b/package/ios/libs/filament/include/utils/Slice.h new file mode 100644 index 00000000..444a3b27 --- /dev/null +++ b/package/ios/libs/filament/include/utils/Slice.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_SLICE_H +#define TNT_UTILS_SLICE_H + +#include + +#include + +#include +#include + +namespace utils { + +/* + * A fixed-size slice of a container + */ +template +class Slice { +public: + using iterator = T*; + using const_iterator = T const*; + using value_type = T; + using reference = T&; + using const_reference = T const&; + using pointer = T*; + using const_pointer = T const*; + using size_type = size_t; + + Slice() noexcept = default; + + Slice(const_iterator begin, const_iterator end) noexcept + : mBegin(const_cast(begin)), + mEnd(const_cast(end)) { + } + + Slice(const_pointer begin, size_type count) noexcept + : mBegin(const_cast(begin)), + mEnd(mBegin + count) { + } + + Slice(Slice const& rhs) noexcept = default; + Slice(Slice&& rhs) noexcept = default; + Slice& operator=(Slice const& rhs) noexcept = default; + Slice& operator=(Slice&& rhs) noexcept = default; + + void set(pointer begin, size_type count) UTILS_RESTRICT noexcept { + mBegin = begin; + mEnd = begin + count; + } + + void set(iterator begin, iterator end) UTILS_RESTRICT noexcept { + mBegin = begin; + mEnd = end; + } + + void swap(Slice& rhs) UTILS_RESTRICT noexcept { + std::swap(mBegin, rhs.mBegin); + std::swap(mEnd, rhs.mEnd); + } + + void clear() UTILS_RESTRICT noexcept { + mBegin = nullptr; + mEnd = nullptr; + } + + // size + size_t size() const UTILS_RESTRICT noexcept { return mEnd - mBegin; } + size_t sizeInBytes() const UTILS_RESTRICT noexcept { return size() * sizeof(T); } + bool empty() const UTILS_RESTRICT noexcept { return size() == 0; } + + // iterators + iterator begin() UTILS_RESTRICT noexcept { return mBegin; } + const_iterator begin() const UTILS_RESTRICT noexcept { return mBegin; } + const_iterator cbegin() const UTILS_RESTRICT noexcept { return this->begin(); } + iterator end() UTILS_RESTRICT noexcept { return mEnd; } + const_iterator end() const UTILS_RESTRICT noexcept { return mEnd; } + const_iterator cend() const UTILS_RESTRICT noexcept { return this->end(); } + + // data access + reference operator[](size_t n) UTILS_RESTRICT noexcept { + assert(n < size()); + return mBegin[n]; + } + + const_reference operator[](size_t n) const UTILS_RESTRICT noexcept { + assert(n < size()); + return mBegin[n]; + } + + reference at(size_t n) UTILS_RESTRICT noexcept { + return operator[](n); + } + + const_reference at(size_t n) const UTILS_RESTRICT noexcept { + return operator[](n); + } + + reference front() UTILS_RESTRICT noexcept { + assert(!empty()); + return *mBegin; + } + + const_reference front() const UTILS_RESTRICT noexcept { + assert(!empty()); + return *mBegin; + } + + reference back() UTILS_RESTRICT noexcept { + assert(!empty()); + return *(this->end() - 1); + } + + const_reference back() const UTILS_RESTRICT noexcept { + assert(!empty()); + return *(this->end() - 1); + } + + pointer data() UTILS_RESTRICT noexcept { + return this->begin(); + } + + const_pointer data() const UTILS_RESTRICT noexcept { + return this->begin(); + } + +protected: + iterator mBegin = nullptr; + iterator mEnd = nullptr; +}; + +} // namespace utils + +#endif // TNT_UTILS_SLICE_H diff --git a/package/ios/libs/filament/include/utils/StructureOfArrays.h b/package/ios/libs/filament/include/utils/StructureOfArrays.h new file mode 100644 index 00000000..a4309584 --- /dev/null +++ b/package/ios/libs/filament/include/utils/StructureOfArrays.h @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_STRUCTUREOFARRAYS_H +#define TNT_UTILS_STRUCTUREOFARRAYS_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include // note: this is safe, see how std::array is used below (inline / private) +#include +#include // for std::random_access_iterator_tag +#include +#include + +namespace utils { + +template +class StructureOfArraysBase { + // number of elements + static constexpr const size_t kArrayCount = sizeof...(Elements); + +public: + using SoA = StructureOfArraysBase; + + using Structure = std::tuple; + + // Type of the Nth array + template + using TypeAt = typename std::tuple_element_t; + + // Number of arrays + static constexpr size_t getArrayCount() noexcept { return kArrayCount; } + + // Size needed to store "size" array elements + static size_t getNeededSize(size_t size) noexcept { + return getOffset(kArrayCount - 1, size) + sizeof(TypeAt) * size; + } + + // -------------------------------------------------------------------------------------------- + + class IteratorValue; + template class Iterator; + using iterator = Iterator; + using const_iterator = Iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + + /* + * An object that represents a reference to the type dereferenced by iterator. + * In other words, it's the return type of iterator::operator*(), and since it + * cannot be a C++ reference (&), it's an object that acts like it. + */ + class IteratorValueRef { + friend class IteratorValue; + friend iterator; + friend const_iterator; + StructureOfArraysBase* const UTILS_RESTRICT soa; + size_t const index; + + IteratorValueRef(StructureOfArraysBase* soa, size_t index) : soa(soa), index(index) { } + + // assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference) + template + IteratorValueRef& assign(IteratorValue const& rhs, std::index_sequence); + + // assigns a value_type to a reference (i.e. assigns to what's pointed to by the reference) + template + IteratorValueRef& assign(IteratorValue&& rhs, std::index_sequence) noexcept; + + // objects pointed to by reference can be swapped, so provide the special swap() function. + friend void swap(IteratorValueRef lhs, IteratorValueRef rhs) { + lhs.soa->swap(lhs.index, rhs.index); + } + + public: + // references can be created by copy-assignment only + IteratorValueRef(IteratorValueRef const& rhs) noexcept : soa(rhs.soa), index(rhs.index) { } + + // copy the content of a reference to the content of this one + IteratorValueRef& operator=(IteratorValueRef const& rhs); + + // move the content of a reference to the content of this one + IteratorValueRef& operator=(IteratorValueRef&& rhs) noexcept; + + // copy a value_type to the content of this reference + IteratorValueRef& operator=(IteratorValue const& rhs) { + return assign(rhs, std::make_index_sequence()); + } + + // move a value_type to the content of this reference + IteratorValueRef& operator=(IteratorValue&& rhs) noexcept { + return assign(rhs, std::make_index_sequence()); + } + + // access the elements of this reference (i.e. the "fields" of the structure) + template TypeAt const& get() const { return soa->elementAt(index); } + template TypeAt& get() { return soa->elementAt(index); } + }; + + + /* + * The value_type of iterator. This is basically the "structure" of the SoA. + * Internally we're using a tuple<> to store the data. + * This object is not trivial to construct, as it copies an entry of the SoA. + */ + class IteratorValue { + friend class IteratorValueRef; + friend iterator; + friend const_iterator; + using Type = std::tuple::type...>; + Type elements; + + template + static Type init(IteratorValueRef const& rhs, std::index_sequence) { + return Type{ rhs.soa->template elementAt(rhs.index)... }; + } + + template + static Type init(IteratorValueRef&& rhs, std::index_sequence) noexcept { + return Type{ std::move(rhs.soa->template elementAt(rhs.index))... }; + } + + public: + IteratorValue(IteratorValue const& rhs) = default; + IteratorValue(IteratorValue&& rhs) noexcept = default; + IteratorValue& operator=(IteratorValue const& rhs) = default; + IteratorValue& operator=(IteratorValue&& rhs) noexcept = default; + + // initialize and assign from a StructureRef + IteratorValue(IteratorValueRef const& rhs) + : elements(init(rhs, std::make_index_sequence())) {} + IteratorValue(IteratorValueRef&& rhs) noexcept + : elements(init(rhs, std::make_index_sequence())) {} + IteratorValue& operator=(IteratorValueRef const& rhs) { return operator=(IteratorValue(rhs)); } + IteratorValue& operator=(IteratorValueRef&& rhs) noexcept { return operator=(IteratorValue(rhs)); } + + // access the elements of this value_Type (i.e. the "fields" of the structure) + template TypeAt const& get() const { return std::get(elements); } + template TypeAt& get() { return std::get(elements); } + }; + + + /* + * An iterator to the SoA. This is only intended to be used with STL's algorithm, e.g.: sort(). + * Normally, SoA is not iterated globally, but rather an array at a time. + * Iterating itself is not too costly, as well as dereferencing by reference. However, + * dereferencing by value is. + */ + template + class Iterator { + friend class StructureOfArraysBase; + CVQualifiedSOAPointer soa; // don't use restrict, can have aliases if multiple iterators are created + size_t index; + + Iterator(CVQualifiedSOAPointer soa, size_t index) : soa(soa), index(index) {} + + public: + using value_type = IteratorValue; + using reference = IteratorValueRef; + using pointer = IteratorValueRef*; // FIXME: this should be a StructurePtr type + using difference_type = ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + Iterator(Iterator const& rhs) noexcept = default; + Iterator& operator=(Iterator const& rhs) = default; + + reference operator*() const { return { soa, index }; } + reference operator*() { return { soa, index }; } + reference operator[](size_t n) { return *(*this + n); } + + template TypeAt const& get() const { return soa->template elementAt(index); } + template TypeAt& get() { return soa->template elementAt(index); } + + Iterator& operator++() { ++index; return *this; } + Iterator& operator--() { --index; return *this; } + Iterator& operator+=(size_t n) { index += n; return *this; } + Iterator& operator-=(size_t n) { index -= n; return *this; } + Iterator operator+(size_t n) const { return { soa, index + n }; } + Iterator operator-(size_t n) const { return { soa, index - n }; } + difference_type operator-(Iterator const& rhs) const { return index - rhs.index; } + bool operator==(Iterator const& rhs) const { return (index == rhs.index); } + bool operator!=(Iterator const& rhs) const { return (index != rhs.index); } + bool operator>=(Iterator const& rhs) const { return (index >= rhs.index); } + bool operator> (Iterator const& rhs) const { return (index > rhs.index); } + bool operator<=(Iterator const& rhs) const { return (index <= rhs.index); } + bool operator< (Iterator const& rhs) const { return (index < rhs.index); } + + // Postfix operator needed by Microsoft STL. + const Iterator operator++(int) { Iterator it(*this); index++; return it; } + const Iterator operator--(int) { Iterator it(*this); index--; return it; } + }; + + iterator begin() noexcept { return { this, 0u }; } + iterator end() noexcept { return { this, mSize }; } + const_iterator begin() const noexcept { return { this, 0u }; } + const_iterator end() const noexcept { return { this, mSize }; } + + // -------------------------------------------------------------------------------------------- + + StructureOfArraysBase() = default; + + explicit StructureOfArraysBase(size_t capacity) { + setCapacity(capacity); + } + + // not copyable for now + StructureOfArraysBase(StructureOfArraysBase const& rhs) = delete; + StructureOfArraysBase& operator=(StructureOfArraysBase const& rhs) = delete; + + // movability is trivial, so support it + StructureOfArraysBase(StructureOfArraysBase&& rhs) noexcept { + using std::swap; + swap(mCapacity, rhs.mCapacity); + swap(mSize, rhs.mSize); + swap(mArrays, rhs.mArrays); + swap(mAllocator, rhs.mAllocator); + } + + StructureOfArraysBase& operator=(StructureOfArraysBase&& rhs) noexcept { + if (this != &rhs) { + using std::swap; + swap(mCapacity, rhs.mCapacity); + swap(mSize, rhs.mSize); + swap(mArrays, rhs.mArrays); + swap(mAllocator, rhs.mAllocator); + } + return *this; + } + + ~StructureOfArraysBase() { + destroy_each(0, mSize); + mAllocator.free(std::get<0>(mArrays)); + } + + // -------------------------------------------------------------------------------------------- + + // return the size the array + size_t size() const noexcept { + return mSize; + } + + // return the capacity of the array + size_t capacity() const noexcept { + return mCapacity; + } + + // set the capacity of the array. the capacity cannot be smaller than the current size, + // the call is a no-op in that case. + UTILS_NOINLINE + void setCapacity(size_t capacity) { + // allocate enough space for "capacity" elements of each array + // capacity cannot change when optional storage is specified + if (capacity >= mSize) { + // TODO: not entirely sure if "max" of all alignments is always correct + constexpr size_t align = std::max({ std::max(alignof(std::max_align_t), alignof(Elements))... }); + const size_t sizeNeeded = getNeededSize(capacity); + void* buffer = mAllocator.alloc(sizeNeeded, align); + auto const oldBuffer = std::get<0>(mArrays); + + // move all the items (one array at a time) from the old allocation to the new + // this also update the array pointers + move_each(buffer, capacity); + + // free the old buffer + mAllocator.free(oldBuffer); + + // and make sure to update the capacity + mCapacity = capacity; + } + } + + void ensureCapacity(size_t needed) { + if (UTILS_UNLIKELY(needed > mCapacity)) { + // not enough space, increase the capacity + const size_t capacity = (needed * 3 + 1) / 2; + setCapacity(capacity); + } + } + + // grow or shrink the array to the given size. When growing, new elements are constructed + // with their default constructor. when shrinking, discarded elements are destroyed. + // If the arrays don't have enough capacity, the capacity is increased accordingly + // (the capacity is set to 3/2 of the asked size). + UTILS_NOINLINE + void resize(size_t needed) { + ensureCapacity(needed); + resizeNoCheck(needed); + if (needed <= mCapacity) { + // TODO: see if we should shrink the arrays + } + } + + void clear() noexcept { + resizeNoCheck(0); + } + + + inline void swap(size_t i, size_t j) noexcept { + forEach([i, j](auto p) { + using std::swap; + swap(p[i], p[j]); + }); + } + + // remove and destroy the last element of each array + inline void pop_back() noexcept { + if (mSize) { + destroy_each(mSize - 1, mSize); + mSize--; + } + } + + // create an element at the end of each array + StructureOfArraysBase& push_back() noexcept { + resize(mSize + 1); + return *this; + } + + StructureOfArraysBase& push_back(Structure&& args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(std::forward(args)); + } + + StructureOfArraysBase& push_back(Elements const& ... args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(args...); + } + + StructureOfArraysBase& push_back(Elements&& ... args) noexcept { + ensureCapacity(mSize + 1); + return push_back_unsafe(std::forward(args)...); + } + + template + struct ElementIndices {}; + + template + struct BuildElementIndices : BuildElementIndices {}; + + template + struct BuildElementIndices<0, Indices...> : ElementIndices {}; + + template + void push_back_unsafe(Structure&& args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::get(args)}; + }() , ...); + } + + template + void push_back_unsafe(Elements const& ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{args}; + }() , ...); + } + + template + void push_back_unsafe(Elements && ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::forward(args)}; + }() , ...); + } + + StructureOfArraysBase& push_back_unsafe(Structure&& args) noexcept { + push_back_unsafe(std::forward(args), BuildElementIndices{}); + return *this; + } + + StructureOfArraysBase& push_back_unsafe(Elements const& ... args) noexcept { + push_back_unsafe(args..., BuildElementIndices{}); + + return *this; + } + + StructureOfArraysBase& push_back_unsafe(Elements&& ... args) noexcept { + push_back_unsafe(std::forward(args)..., BuildElementIndices{}); + return *this; + } + + template + void forEach(F&& f, ARGS&& ... args) { + for_each(mArrays, [&](size_t, auto* p) { + f(p, std::forward(args)...); + }); + } + + // return a pointer to the first element of the ElementIndex]th array + template + TypeAt* data() noexcept { + return std::get(mArrays); + } + + template + TypeAt const* data() const noexcept { + return std::get(mArrays); + } + + template + TypeAt* begin() noexcept { + return std::get(mArrays); + } + + template + TypeAt const* begin() const noexcept { + return std::get(mArrays); + } + + template + TypeAt* end() noexcept { + return std::get(mArrays) + size(); + } + + template + TypeAt const* end() const noexcept { + return std::get(mArrays) + size(); + } + + template + Slice> slice() noexcept { + return { begin(), end() }; + } + + template + Slice> slice() const noexcept { + return { begin(), end() }; + } + + // return a reference to the index'th element of the ElementIndex'th array + template + TypeAt& elementAt(size_t index) noexcept { + return data()[index]; + } + + template + TypeAt const& elementAt(size_t index) const noexcept { + return data()[index]; + } + + // return a reference to the last element of the ElementIndex'th array + template + TypeAt& back() noexcept { + return data()[size() - 1]; + } + + template + TypeAt const& back() const noexcept { + return data()[size() - 1]; + } + + template + struct Field { + SoA& soa; + IndexType i; + using Type = typename SoA::template TypeAt; + + UTILS_ALWAYS_INLINE Field& operator = (Field&& rhs) noexcept { + soa.elementAt(i) = soa.elementAt(rhs.i); + return *this; + } + + // auto-conversion to the field's type + UTILS_ALWAYS_INLINE operator Type&() noexcept { + return soa.elementAt(i); + } + UTILS_ALWAYS_INLINE operator Type const&() const noexcept { + return soa.elementAt(i); + } + // dereferencing the selected field + UTILS_ALWAYS_INLINE Type& operator ->() noexcept { + return soa.elementAt(i); + } + UTILS_ALWAYS_INLINE Type const& operator ->() const noexcept { + return soa.elementAt(i); + } + // address-of the selected field + UTILS_ALWAYS_INLINE Type* operator &() noexcept { + return &soa.elementAt(i); + } + UTILS_ALWAYS_INLINE Type const* operator &() const noexcept { + return &soa.elementAt(i); + } + // assignment to the field + UTILS_ALWAYS_INLINE Type const& operator = (Type const& other) noexcept { + return (soa.elementAt(i) = other); + } + UTILS_ALWAYS_INLINE Type const& operator = (Type&& other) noexcept { + return (soa.elementAt(i) = other); + } + // comparisons + UTILS_ALWAYS_INLINE bool operator==(Type const& other) const { + return (soa.elementAt(i) == other); + } + UTILS_ALWAYS_INLINE bool operator!=(Type const& other) const { + return (soa.elementAt(i) != other); + } + // calling the field + template + UTILS_ALWAYS_INLINE decltype(auto) operator()(ARGS&& ... args) noexcept { + return soa.elementAt(i)(std::forward(args)...); + } + template + UTILS_ALWAYS_INLINE decltype(auto) operator()(ARGS&& ... args) const noexcept { + return soa.elementAt(i)(std::forward(args)...); + } + }; + +private: + template + inline typename std::enable_if::type + for_each(std::tuple&, FuncT) {} + + template + inline typename std::enable_if::type + for_each(std::tuple& t, FuncT f) { + f(I, std::get(t)); + for_each(t, f); + } + + template + inline typename std::enable_if::type + for_each_index(std::tuple&, FuncT) {} + + template + inline typename std::enable_if::type + for_each_index(std::tuple& t, FuncT f) { + f.template operator()(std::get(t)); + for_each_index(t, f); + } + + inline void resizeNoCheck(size_t needed) noexcept { + assert_invariant(mCapacity >= needed); + if (needed < mSize) { + // we shrink the arrays + destroy_each(needed, mSize); + } else if (needed > mSize) { + // we grow the arrays + construct_each(mSize, needed); + } + // record the new size of the arrays + mSize = needed; + } + + // 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]; + } + + static inline std::array getOffsets(size_t capacity) noexcept { + // compute the required size of each array + const size_t sizes[] = { (sizeof(Elements) * capacity)... }; + + // we align each array to at least the same alignment guaranteed by malloc + constexpr size_t const alignments[] = { std::max(alignof(std::max_align_t), alignof(Elements))... }; + + // hopefully most of this gets unrolled and inlined + std::array offsets; + offsets[0] = 0; + UTILS_UNROLL + for (size_t i = 1; i < kArrayCount; i++) { + size_t unalignment = (offsets[i - 1] + sizes[i - 1]) % alignments[i]; + size_t alignment = unalignment ? (alignments[i] - unalignment) : 0; + offsets[i] = offsets[i - 1] + (sizes[i - 1] + alignment); + assert_invariant(offsets[i] % alignments[i] == 0); + } + return offsets; + } + + void construct_each(size_t from, size_t to) noexcept { + forEach([from, to](auto p) { + using T = typename std::decay::type; + // note: scalar types like int/float get initialized to zero + if constexpr (!std::is_trivially_default_constructible_v) { + for (size_t i = from; i < to; i++) { + new(p + i) T(); + } + } + }); + } + + void destroy_each(size_t from, size_t to) noexcept { + forEach([from, to](auto p) { + using T = typename std::decay::type; + if constexpr (!std::is_trivially_destructible_v) { + for (size_t i = from; i < to; i++) { + p[i].~T(); + } + } + }); + } + + void move_each(void* buffer, size_t capacity) noexcept { + auto offsets = getOffsets(capacity); + size_t index = 0; + if (mSize) { + auto size = mSize; // placate a compiler warning + forEach([buffer, &index, &offsets, size](auto p) { + using T = typename std::decay::type; + T* UTILS_RESTRICT b = static_cast(buffer); + + // go through each element and move them from the old array to the new + // then destroy them from the old array + T* UTILS_RESTRICT const arrayPointer = + reinterpret_cast(uintptr_t(b) + offsets[index]); + + // for trivial cases, just call memcpy() + if constexpr (std::is_trivially_copyable_v && + std::is_trivially_destructible_v) { + memcpy(arrayPointer, p, size * sizeof(T)); + } else { + for (size_t i = 0; i < size; i++) { + // we move an element by using the in-place move-constructor + new(arrayPointer + i) T(std::move(p[i])); + if constexpr (!std::is_trivially_destructible_v) { + // and delete them by calling the destructor directly + p[i].~T(); + } + } + } + index++; + }); + } + + // update the pointers + for_each(mArrays, [buffer, &offsets](size_t i, auto&& p) { + using Type = std::remove_reference_t; + p = Type((char*)buffer + offsets[i]); + }); + } + + // capacity in array elements + size_t mCapacity = 0; + // size in array elements + size_t mSize = 0; + // N pointers to each arrays + std::tuple...> mArrays{}; + Allocator mAllocator; +}; + + +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::operator=( + StructureOfArraysBase::IteratorValueRef const& rhs) { + return operator=(IteratorValue(rhs)); +} + +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::operator=( + StructureOfArraysBase::IteratorValueRef&& rhs) noexcept { + return operator=(IteratorValue(rhs)); +} + +template +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::assign( + StructureOfArraysBase::IteratorValue const& rhs, std::index_sequence) { + // implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue const& rhs) + auto UTILS_UNUSED l = { (soa->elementAt(index) = std::get(rhs.elements), 0)... }; + return *this; +} + +template +template +inline +typename StructureOfArraysBase::IteratorValueRef& +StructureOfArraysBase::IteratorValueRef::assign( + StructureOfArraysBase::IteratorValue&& rhs, std::index_sequence) noexcept { + // implements IteratorValueRef& IteratorValueRef::operator=(IteratorValue&& rhs) noexcept + auto UTILS_UNUSED l = { + (soa->elementAt(index) = std::move(std::get(rhs.elements)), 0)... }; + return *this; +} + +template +using StructureOfArrays = StructureOfArraysBase, Elements ...>; + +} // namespace utils + +#endif // TNT_UTILS_STRUCTUREOFARRAYS_H + diff --git a/package/ios/libs/filament/include/utils/algorithm.h b/package/ios/libs/filament/include/utils/algorithm.h new file mode 100644 index 00000000..ea5ca44f --- /dev/null +++ b/package/ios/libs/filament/include/utils/algorithm.h @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef TNT_UTILS_ALGORITHM_H +#define TNT_UTILS_ALGORITHM_H + +#include + +#include // for std::enable_if + +#include +#include + +namespace utils { + +namespace details { + +template +constexpr inline T popcount(T v) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::popcount() only support up to 128 bits"); + constexpr T ONES = ~T(0); + v = v - ((v >> 1u) & ONES / 3); + v = (v & ONES / 15 * 3) + ((v >> 2u) & ONES / 15 * 3); + v = (v + (v >> 4u)) & ONES / 255 * 15; + return (T) (v * (ONES / 255)) >> (sizeof(T) - 1) * CHAR_BIT; +} + +template::value>> +constexpr inline T clz(T x) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::clz() only support up to 128 bits"); + x |= (x >> 1u); + x |= (x >> 2u); + x |= (x >> 4u); + x |= (x >> 8u); + x |= (x >> 16u); + if constexpr (sizeof(T) * CHAR_BIT >= 64) { // just to silence compiler warning + x |= (x >> 32u); + } + if constexpr (sizeof(T) * CHAR_BIT >= 128) { // just to silence compiler warning + x |= (x >> 64u); + } + return T(sizeof(T) * CHAR_BIT) - details::popcount(x); +} + +template::value>> +constexpr inline T ctz(T x) noexcept { + static_assert(sizeof(T) * CHAR_BIT <= 64, "details::ctz() only support up to 64 bits"); + T c = sizeof(T) * CHAR_BIT; +#if defined(_MSC_VER) + // equivalent to x & -x, but MSVC yield a warning for using unary minus operator on unsigned types + x &= (~x + 1); +#else + // equivalent to x & (~x + 1), but some compilers generate a better sequence on ARM + x &= -x; +#endif + if (x) c--; + if (sizeof(T) * CHAR_BIT >= 64) { + if (x & T(0x00000000FFFFFFFF)) c -= 32; + } + if (x & T(0x0000FFFF0000FFFF)) c -= 16; + if (x & T(0x00FF00FF00FF00FF)) c -= 8; + if (x & T(0x0F0F0F0F0F0F0F0F)) c -= 4; + if (x & T(0x3333333333333333)) c -= 2; + if (x & T(0x5555555555555555)) c -= 1; + return c; +} + +} // namespace details + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE clz(unsigned int x) noexcept { +#if __has_builtin(__builtin_clz) + return __builtin_clz(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE clz(unsigned long x) noexcept { +#if __has_builtin(__builtin_clzl) + return __builtin_clzl(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE clz(unsigned long long x) noexcept { +#if __has_builtin(__builtin_clzll) + return __builtin_clzll(x); +#else + return details::clz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE ctz(unsigned int x) noexcept { +#if __has_builtin(__builtin_ctz) + return __builtin_ctz(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE ctz(unsigned long x) noexcept { +#if __has_builtin(__builtin_ctzl) + return __builtin_ctzl(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE ctz(unsigned long long x) noexcept { +#if __has_builtin(__builtin_ctzll) + return __builtin_ctzll(x); +#else + return details::ctz(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned int UTILS_ALWAYS_INLINE popcount(unsigned int x) noexcept { +#if __has_builtin(__builtin_popcount) + return __builtin_popcount(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long UTILS_ALWAYS_INLINE popcount(unsigned long x) noexcept { +#if __has_builtin(__builtin_popcountl) + return __builtin_popcountl(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +unsigned long long UTILS_ALWAYS_INLINE popcount(unsigned long long x) noexcept { +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(x); +#else + return details::popcount(x); +#endif +} + +constexpr inline UTILS_PUBLIC UTILS_PURE +uint8_t UTILS_ALWAYS_INLINE popcount(uint8_t x) noexcept { + return (uint8_t)popcount((unsigned int)x); +} + +template::value && std::is_unsigned::value>> +constexpr inline UTILS_PUBLIC UTILS_PURE +T log2i(T x) noexcept { + return (sizeof(x) * 8 - 1u) - clz(x); +} + +template +inline UTILS_PUBLIC +RandomAccessIterator partition_point( + RandomAccessIterator first, RandomAccessIterator last, COMPARE pred, + bool assume_power_of_two = false) { + size_t len = last - first; + + if (!assume_power_of_two) { + // handle non power-of-two sized arrays. If it's POT, the next line is a no-op + // and gets optimized out if the size is known at compile time. + len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2 + size_t difference = (last - first) - len; + first += !difference || pred(first[len]) ? difference : 0; + } + + while (len) { + // The number of repetitions here doesn't affect the result. We manually unroll the loop + // twice, to guarantee we have at least two iterations without branches (for the case + // where the size is not known at compile time + first += pred(first[len>>=1u]) ? len : 0; + first += pred(first[len>>=1u]) ? len : 0; + } + first += pred(*first); + return first; +} + +template +#if __has_builtin(__builtin_bit_cast) +constexpr +#else +inline +#endif +Dest bit_cast(const Source& source) noexcept { +#if __has_builtin(__builtin_bit_cast) + return __builtin_bit_cast(Dest, source); +#else + static_assert(sizeof(Dest) == sizeof(Source), + "bit_cast requires source and destination to be the same size"); + static_assert(std::is_trivially_copyable_v, + "bit_cast requires the destination type to be copyable"); + static_assert(std::is_trivially_copyable_v, + "bit_cast requires the source type to be copyable"); + Dest dest; + memcpy(&dest, &source, sizeof(dest)); + return dest; +#endif +} + +} // namespace utils + +#endif // TNT_UTILS_ALGORITHM_H diff --git a/package/ios/libs/filament/include/utils/bitset.h b/package/ios/libs/filament/include/utils/bitset.h new file mode 100644 index 00000000..281e5dfc --- /dev/null +++ b/package/ios/libs/filament/include/utils/bitset.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_BITSET_H +#define TNT_UTILS_BITSET_H + +#include +#include +#include + +#include +#include +#include + +#include // for std::fill +#include +#include + +#if defined(__ARM_NEON) +# if defined(__ARM_ACLE) && defined(__aarch64__) +# include +# define TNT_UTILS_BITSET_USE_NEON 1 +# endif +#endif + +namespace utils { + +/* + * This bitset<> class is different from std::bitset<> in that it allows us to control + * the exact storage size. This is useful for small bitset (e.g. < 64, on 64-bits machines). + * It also allows for lexicographical compares (i.e. sorting). + */ + +template::value && + std::is_unsigned::value>::type> +class UTILS_PUBLIC bitset { + T storage[N]; + +public: + static constexpr T BITS_PER_WORD = sizeof(T) * 8; + static constexpr T BIT_COUNT = BITS_PER_WORD * N; + static constexpr T WORLD_COUNT = N; + using container_type = T; + + bitset() noexcept { + std::fill(std::begin(storage), std::end(storage), 0); + } + + T getBitsAt(size_t n) const noexcept { + assert_invariant(n + void forEachSetBit(F exec) const noexcept { + for (size_t i = 0; i < N; i++) { + T v = storage[i]; + while (v) { + T k = utils::ctz(v); + v &= ~(T(1) << k); + exec(size_t(k + BITS_PER_WORD * i)); + } + } + } + + size_t size() const noexcept { return N * BITS_PER_WORD; } + + bool test(size_t bit) const noexcept { return operator[](bit); } + + void set(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] |= T(1) << (b % BITS_PER_WORD); + } + + void set(size_t b, bool value) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] &= ~(T(1) << (b % BITS_PER_WORD)); + storage[b / BITS_PER_WORD] |= T(value) << (b % BITS_PER_WORD); + } + + void unset(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] &= ~(T(1) << (b % BITS_PER_WORD)); + } + + void flip(size_t b) noexcept { + assert_invariant(b / BITS_PER_WORD < N); + storage[b / BITS_PER_WORD] ^= T(1) << (b % BITS_PER_WORD); + } + + + void reset() noexcept { + std::fill(std::begin(storage), std::end(storage), 0); + } + + bool operator[](size_t b) const noexcept { + assert_invariant(b / BITS_PER_WORD < N); + return bool(storage[b / BITS_PER_WORD] & (T(1) << (b % BITS_PER_WORD))); + } + + size_t count() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0 && BIT_COUNT / 128 < 31) { + // Use NEON for bitset multiple of 128 bits. + // The intermediate computation can't handle more than 31*128 bits because + // intermediate counts must be 8 bits. + uint8x16_t const* const p = (uint8x16_t const*) storage; + uint8x16_t counts = vcntq_u8(p[0]); + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + counts += vcntq_u8(p[i]); + } + return vaddlvq_u8(counts); + } else +#endif + { + T r = utils::popcount(storage[0]); + for (size_t i = 1; i < N; ++i) { + r += utils::popcount(storage[i]); + } + return r; + } + } + + bool any() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint64x2_t const* const p = (uint64x2_t const*) storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r |= p[i]; + } + return bool(r[0] | r[1]); + } else +#endif + { + T r = storage[0]; + for (size_t i = 1; i < N; ++i) { + r |= storage[i]; + } + return bool(r); + } + } + + bool none() const noexcept { + return !any(); + } + + bool all() const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint64x2_t const* const p = (uint64x2_t const*) storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r &= p[i]; + } + return T(~(r[0] & r[1])) == T(0); + } else +#endif + { + T r = storage[0]; + for (size_t i = 1; i < N; ++i) { + r &= storage[i]; + } + return T(~r) == T(0); + } + } + + bool operator!=(const bitset& b) const noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + bitset temp(*this ^ b); + uint64x2_t const* const p = (uint64x2_t const*) temp.storage; + uint64x2_t r = p[0]; + for (size_t i = 1; i < BIT_COUNT / 128; ++i) { + r |= p[i]; + } + return bool(r[0] | r[1]); + } else +#endif + { + T r = storage[0] ^ b.storage[0]; + for (size_t i = 1; i < N; ++i) { + r |= storage[i] ^ b.storage[i]; + } + return bool(r); + } + } + + bool operator==(const bitset& b) const noexcept { + return !operator!=(b); + } + + bitset& operator&=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] &= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] &= b.storage[i]; + } + } + return *this; + } + + bitset& operator|=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] |= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] |= b.storage[i]; + } + } + return *this; + } + + bitset& operator^=(const bitset& b) noexcept { +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) storage; + uint8x16_t const* const q = (uint8x16_t const*) b.storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] ^= q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + storage[i] ^= b.storage[i]; + } + } + return *this; + } + + bitset operator~() const noexcept { + bitset r; +#if defined(TNT_UTILS_BITSET_USE_NEON) + if (BIT_COUNT % 128 == 0) { + uint8x16_t* const p = (uint8x16_t*) r.storage; + uint8x16_t const* const q = (uint8x16_t const*) storage; + for (size_t i = 0; i < BIT_COUNT / 128; ++i) { + p[i] = ~q[i]; + } + } else +#endif + { + for (size_t i = 0; i < N; ++i) { + r.storage[i] = ~storage[i]; + } + } + return r; + } + +private: + friend bool operator<(bitset const& lhs, bitset const& rhs) noexcept { + return std::lexicographical_compare( + std::begin(lhs.storage), std::end(lhs.storage), + std::begin(rhs.storage), std::end(rhs.storage) + ); + } + + friend bitset operator&(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) &= rhs; + } + + friend bitset operator|(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) |= rhs; + } + + friend bitset operator^(const bitset& lhs, const bitset& rhs) noexcept { + return bitset(lhs) ^= rhs; + } +}; + +using bitset8 = bitset; +using bitset32 = bitset; +using bitset64 = bitset; +using bitset128 = bitset; +using bitset256 = bitset; + +static_assert(sizeof(bitset8) == 1, "bitset8 isn't 8 bits!"); +static_assert(sizeof(bitset32) == 4, "bitset32 isn't 32 bits!"); +static_assert(sizeof(bitset64) == 8, "bitset64 isn't 64 bits!"); +static_assert(sizeof(bitset128) == 16, "bitset128 isn't 128 bits!"); +static_assert(sizeof(bitset256) == 32, "bitset256 isn't 256 bits!"); + +} // namespace utils + +#endif // TNT_UTILS_BITSET_H diff --git a/package/ios/libs/filament/include/utils/compiler.h b/package/ios/libs/filament/include/utils/compiler.h new file mode 100644 index 00000000..710c901e --- /dev/null +++ b/package/ios/libs/filament/include/utils/compiler.h @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef TNT_UTILS_COMPILER_H +#define TNT_UTILS_COMPILER_H + +// compatibility with non-clang compilers... +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if __has_attribute(visibility) +# define UTILS_PUBLIC __attribute__((visibility("default"))) +#else +# define UTILS_PUBLIC +#endif + +#if __has_attribute(deprecated) +# define UTILS_DEPRECATED [[deprecated]] +#else +# define UTILS_DEPRECATED +#endif + +#if __has_attribute(packed) +# define UTILS_PACKED __attribute__((packed)) +#else +# define UTILS_PACKED +#endif + +#if __has_attribute(noreturn) +# define UTILS_NORETURN __attribute__((noreturn)) +#else +# define UTILS_NORETURN +#endif + +#if __has_attribute(fallthrough) +# define UTILS_FALLTHROUGH [[fallthrough]] +#else +# define UTILS_FALLTHROUGH +#endif + +#if __has_attribute(visibility) +# ifndef TNT_DEV +# define UTILS_PRIVATE __attribute__((visibility("hidden"))) +# else +# define UTILS_PRIVATE +# endif +#else +# define UTILS_PRIVATE +#endif + +#define UTILS_NO_SANITIZE_THREAD +#if __has_feature(thread_sanitizer) +#undef UTILS_NO_SANITIZE_THREAD +#define UTILS_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread"))) +#endif + +#define UTILS_HAS_SANITIZE_THREAD 0 +#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#undef UTILS_HAS_SANITIZE_THREAD +#define UTILS_HAS_SANITIZE_THREAD 1 +#endif + +#define UTILS_HAS_SANITIZE_MEMORY 0 +#if __has_feature(memory_sanitizer) +#undef UTILS_HAS_SANITIZE_MEMORY +#define UTILS_HAS_SANITIZE_MEMORY 1 +#endif + +/* + * helps the compiler's optimizer predicting branches + */ +#if __has_builtin(__builtin_expect) +# ifdef __cplusplus +# define UTILS_LIKELY( exp ) (__builtin_expect( !!(exp), true )) +# define UTILS_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) +# else +# define UTILS_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) +# define UTILS_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) +# endif +#else +# define UTILS_LIKELY( exp ) (!!(exp)) +# define UTILS_UNLIKELY( exp ) (!!(exp)) +#endif + +#if __has_builtin(__builtin_prefetch) +# define UTILS_PREFETCH( exp ) (__builtin_prefetch(exp)) +#else +# define UTILS_PREFETCH( exp ) +#endif + +#if __has_builtin(__builtin_assume) +# define UTILS_ASSUME( exp ) (__builtin_assume(exp)) +#else +# define UTILS_ASSUME( exp ) +#endif + +#if (defined(__i386__) || defined(__x86_64__)) +# define UTILS_HAS_HYPER_THREADING 1 // on x86 we assume we have hyper-threading. +#else +# define UTILS_HAS_HYPER_THREADING 0 +#endif + +#if defined(FILAMENT_SINGLE_THREADED) +# define UTILS_HAS_THREADING 0 +#elif defined(__EMSCRIPTEN__) +# if defined(__EMSCRIPTEN_PTHREADS__) && defined(FILAMENT_WASM_THREADS) +# define UTILS_HAS_THREADING 1 +# else +# define UTILS_HAS_THREADING 0 +# endif +#else +# define UTILS_HAS_THREADING 1 +#endif + +#if __has_attribute(noinline) +#define UTILS_NOINLINE __attribute__((noinline)) +#else +#define UTILS_NOINLINE +#endif + +#if __has_attribute(always_inline) +#define UTILS_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define UTILS_ALWAYS_INLINE +#endif + +#if __has_attribute(pure) +#define UTILS_PURE __attribute__((pure)) +#else +#define UTILS_PURE +#endif + +#if __has_attribute(maybe_unused) || (defined(_MSC_VER) && _MSC_VER >= 1911) +#define UTILS_UNUSED [[maybe_unused]] +#define UTILS_UNUSED_IN_RELEASE [[maybe_unused]] +#elif __has_attribute(unused) +#define UTILS_UNUSED __attribute__((unused)) +#define UTILS_UNUSED_IN_RELEASE __attribute__((unused)) +#else +#define UTILS_UNUSED +#define UTILS_UNUSED_IN_RELEASE +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define UTILS_RESTRICT __restrict +#elif (defined(__clang__) || defined(__GNUC__)) +# define UTILS_RESTRICT __restrict__ +#else +# define UTILS_RESTRICT +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 1 +#elif __has_feature(cxx_thread_local) +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 1 +#else +# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 0 +#endif + +#if defined(__clang__) +#define UTILS_NONNULL _Nonnull +#define UTILS_NULLABLE _Nullable +#else +#define UTILS_NONNULL +#define UTILS_NULLABLE +#endif + +#if defined(_MSC_VER) +// MSVC does not support loop unrolling hints +# define UTILS_UNROLL +# define UTILS_NOUNROLL +#else +// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax. +# define UTILS_UNROLL _Pragma("unroll") +# define UTILS_NOUNROLL _Pragma("nounroll") +#endif + +#if __has_feature(cxx_rtti) || defined(_CPPRTTI) +# define UTILS_HAS_RTTI 1 +#else +# define UTILS_HAS_RTTI 0 +#endif + +#ifdef __ARM_ACLE +# include +# define UTILS_WAIT_FOR_INTERRUPT() __wfi() +# define UTILS_WAIT_FOR_EVENT() __wfe() +# define UTILS_BROADCAST_EVENT() __sev() +# define UTILS_SIGNAL_EVENT() __sevl() +# define UTILS_PAUSE() __yield() +# define UTILS_PREFETCHW(addr) __pldx(1, 0, 0, addr) +#else // !__ARM_ACLE +# if (defined(__i386__) || defined(__x86_64__)) +# define UTILS_X86_PAUSE {__asm__ __volatile__( "rep; nop" : : : "memory" );} +# define UTILS_WAIT_FOR_INTERRUPT() UTILS_X86_PAUSE +# define UTILS_WAIT_FOR_EVENT() UTILS_X86_PAUSE +# define UTILS_BROADCAST_EVENT() +# define UTILS_SIGNAL_EVENT() +# define UTILS_PAUSE() UTILS_X86_PAUSE +# define UTILS_PREFETCHW(addr) UTILS_PREFETCH(addr) +# else // !x86 +# define UTILS_WAIT_FOR_INTERRUPT() +# define UTILS_WAIT_FOR_EVENT() +# define UTILS_BROADCAST_EVENT() +# define UTILS_SIGNAL_EVENT() +# define UTILS_PAUSE() +# define UTILS_PREFETCHW(addr) UTILS_PREFETCH(addr) +# endif // x86 +#endif // __ARM_ACLE + + +// ssize_t is a POSIX type. +#if defined(WIN32) || defined(_WIN32) +#include +typedef SSIZE_T ssize_t; +#endif + +#ifdef _MSC_VER +# define UTILS_EMPTY_BASES __declspec(empty_bases) +#else +# define UTILS_EMPTY_BASES +#endif + +#if defined(WIN32) || defined(_WIN32) + #define IMPORTSYMB __declspec(dllimport) +#else + #define IMPORTSYMB +#endif + +#if defined(_MSC_VER) && !defined(__PRETTY_FUNCTION__) +# define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + + +#if defined(_MSC_VER) +# define UTILS_WARNING_PUSH _Pragma("warning( push )") +# define UTILS_WARNING_POP _Pragma("warning( pop )") +# define UTILS_WARNING_ENABLE_PADDED _Pragma("warning(1: 4324)") +#elif defined(__clang__) +# define UTILS_WARNING_PUSH _Pragma("clang diagnostic push") +# define UTILS_WARNING_POP _Pragma("clang diagnostic pop") +# define UTILS_WARNING_ENABLE_PADDED _Pragma("clang diagnostic warning \"-Wpadded\"") +#else +# define UTILS_WARNING_PUSH +# define UTILS_WARNING_POP +# define UTILS_WARNING_ENABLE_PADDED +#endif + +#endif // TNT_UTILS_COMPILER_H diff --git a/package/ios/libs/filament/include/utils/compressed_pair.h b/package/ios/libs/filament/include/utils/compressed_pair.h new file mode 100644 index 00000000..62bf2de4 --- /dev/null +++ b/package/ios/libs/filament/include/utils/compressed_pair.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_COMPRESSED_PAIR_H +#define TNT_UTILS_COMPRESSED_PAIR_H + +#include +#include + +namespace utils { + +template +struct dependent_type : public T { +}; + +template, bool> = true> +struct compressed_pair : private T1, private T2 { + + template, Dummy>::value && + dependent_type, Dummy>::value>> + compressed_pair() : T1(), T2() {} + + template + compressed_pair(U1&& other1, U2&& other2) + : T1(std::forward(other1)), + T2(std::forward(other2)) {} + + T1& first() noexcept { + return static_cast(*this); + } + + T2& second() noexcept { + return static_cast(*this); + } + + T1 const& first() const noexcept { + return static_cast(*this); + } + + T2 const& second() const noexcept { + return static_cast(*this); + } + + void swap(compressed_pair& other) noexcept { + using std::swap; + swap(first(), other.first()); + swap(second(), other.second()); + } +}; + +} // namespace utils + +#endif // TNT_UTILS_COMPRESSED_PAIR_H diff --git a/package/ios/libs/filament/include/utils/debug.h b/package/ios/libs/filament/include/utils/debug.h new file mode 100644 index 00000000..4c118725 --- /dev/null +++ b/package/ios/libs/filament/include/utils/debug.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_UTILS_DEBUG_H +#define TNT_UTILS_DEBUG_H + +#include + +namespace utils { +void panic(const char *func, const char * file, int line, const char *assertion) noexcept; +} // namespace filament + +#ifdef NDEBUG +# define assert_invariant(e) ((void)0) +#else +# define assert_invariant(e) \ + (UTILS_LIKELY(e) ? ((void)0) : utils::panic(__func__, __FILE__, __LINE__, #e)) +#endif // NDEBUG + +#endif // TNT_UTILS_DEBUG_H diff --git a/package/ios/libs/filament/include/utils/generic/Mutex.h b/package/ios/libs/filament/include/utils/generic/Mutex.h new file mode 100644 index 00000000..d5976d04 --- /dev/null +++ b/package/ios/libs/filament/include/utils/generic/Mutex.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef TNT_UTILS_GENERIC_MUTEX_H +#define TNT_UTILS_GENERIC_MUTEX_H + +#include + +namespace utils { + +using Mutex = std::mutex; + +} // namespace utils + +#endif // TNT_UTILS_GENERIC_MUTEX_H diff --git a/package/ios/libs/filament/include/utils/memalign.h b/package/ios/libs/filament/include/utils/memalign.h new file mode 100644 index 00000000..4c048bff --- /dev/null +++ b/package/ios/libs/filament/include/utils/memalign.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef TNT_UTILS_MEMALIGN_H +#define TNT_UTILS_MEMALIGN_H + +#include + +#include +#include +#include + +#if defined(WIN32) +#include +#endif + +namespace utils { + +inline void* aligned_alloc(size_t size, size_t align) noexcept { + // 'align' must be a power of two and a multiple of sizeof(void*) + align = (align < sizeof(void*)) ? sizeof(void*) : align; + assert(align && !(align & align - 1)); + assert((align % sizeof(void*)) == 0); + + void* p = nullptr; + +#if defined(WIN32) + p = ::_aligned_malloc(size, align); +#else + ::posix_memalign(&p, align, size); +#endif + return p; +} + +inline void aligned_free(void* p) noexcept { +#if defined(WIN32) + ::_aligned_free(p); +#else + ::free(p); +#endif +} + +/* + * This allocator can be used with std::vector for instance to ensure all items are aligned + * to their alignof(). e.g. + * + * template + * using aligned_vector = std::vector>; + * + * aligned_vector foos; + * + */ +template +class STLAlignedAllocator { + static_assert(!(alignof(TYPE) & (alignof(TYPE) - 1)), "alignof(T) must be a power of two"); + +public: + using value_type = TYPE; + using pointer = TYPE*; + using const_pointer = const TYPE*; + using reference = TYPE&; + using const_reference = const TYPE&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::true_type; + + template + struct rebind { using other = STLAlignedAllocator; }; + + inline STLAlignedAllocator() noexcept = default; + + template + inline explicit STLAlignedAllocator(const STLAlignedAllocator&) noexcept {} + + inline ~STLAlignedAllocator() noexcept = default; + + inline pointer allocate(size_type n) noexcept { + return (pointer)aligned_alloc(n * sizeof(value_type), alignof(TYPE)); + } + + inline void deallocate(pointer p, size_type) { + aligned_free(p); + } + + // stateless allocators are always equal + template + bool operator==(const STLAlignedAllocator&) const noexcept { + return true; + } + + template + bool operator!=(const STLAlignedAllocator&) const noexcept { + return false; + } +}; + +} // namespace utils + +#endif // TNT_UTILS_MEMALIGN_H diff --git a/package/ios/libs/filament/include/utils/ostream.h b/package/ios/libs/filament/include/utils/ostream.h new file mode 100644 index 00000000..623cf9c0 --- /dev/null +++ b/package/ios/libs/filament/include/utils/ostream.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef TNT_UTILS_OSTREAM_H +#define TNT_UTILS_OSTREAM_H + +#include +#include +#include + +#include +#include +#include + +namespace utils::io { + +struct ostream_; + +class UTILS_PUBLIC ostream : protected utils::PrivateImplementation { + friend struct ostream_; + +public: + virtual ~ostream(); + + ostream& operator<<(short value) noexcept; + ostream& operator<<(unsigned short value) noexcept; + + ostream& operator<<(char value) noexcept; + ostream& operator<<(unsigned char value) noexcept; + + ostream& operator<<(int value) noexcept; + ostream& operator<<(unsigned int value) noexcept; + + ostream& operator<<(long value) noexcept; + ostream& operator<<(unsigned long value) noexcept; + + ostream& operator<<(long long value) noexcept; + ostream& operator<<(unsigned long long value) noexcept; + + ostream& operator<<(float value) noexcept; + ostream& operator<<(double value) noexcept; + ostream& operator<<(long double value) noexcept; + + ostream& operator<<(bool value) noexcept; + + ostream& operator<<(const void* value) noexcept; + + ostream& operator<<(const char* string) noexcept; + ostream& operator<<(const unsigned char* string) noexcept; + + ostream& operator<<(std::string const& s) noexcept; + ostream& operator<<(std::string_view const& s) noexcept; + + ostream& operator<<(ostream& (* f)(ostream&)) noexcept { return f(*this); } + + ostream& dec() noexcept; + ostream& hex() noexcept; + + /*! @cond PRIVATE */ + // Sets a consumer of the log. The consumer is invoked on flush() and replaces the default. + // Thread safe and reentrant. + using ConsumerCallback = void(*)(void*, char const*); + void setConsumer(ConsumerCallback consumer, void* user) noexcept; + /*! @endcond */ + +protected: + ostream& print(const char* format, ...) noexcept; + + class Buffer { + public: + Buffer() noexcept; + ~Buffer() noexcept; + + Buffer(const Buffer&) = delete; + Buffer& operator=(const Buffer&) = delete; + + const char* get() const noexcept { return buffer; } + + std::pair grow(size_t s) noexcept; + void advance(ssize_t n) noexcept; + void reset() noexcept; + + private: + void reserve(size_t newSize) noexcept; + + char* buffer = nullptr; // buffer address + char* curr = nullptr; // current pointer + size_t size = 0; // size remaining + size_t capacity = 0; // total capacity of the buffer + }; + + Buffer& getBuffer() noexcept; + Buffer const& getBuffer() const noexcept; + +private: + virtual ostream& flush() noexcept = 0; + + friend ostream& hex(ostream& s) noexcept; + friend ostream& dec(ostream& s) noexcept; + friend ostream& endl(ostream& s) noexcept; + UTILS_PUBLIC friend ostream& flush(ostream& s) noexcept; + + enum type { + SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, FLOAT, DOUBLE, + LONG_DOUBLE + }; + + const char* getFormat(type t) const noexcept; +}; + +// handles utils::bitset +inline ostream& operator << (ostream& o, utils::bitset32 const& s) noexcept { + return o << (void*)uintptr_t(s.getValue()); +} + +// handles vectors from libmath (but we do this generically, without needing a dependency on libmath) +template class VECTOR, typename T> +inline ostream& operator<<(ostream& stream, const VECTOR& v) { + stream << "< "; + for (size_t i = 0; i < v.size() - 1; i++) { + stream << v[i] << ", "; + } + stream << v[v.size() - 1] << " >"; + return stream; +} + +inline ostream& hex(ostream& s) noexcept { return s.hex(); } +inline ostream& dec(ostream& s) noexcept { return s.dec(); } +inline ostream& endl(ostream& s) noexcept { return flush(s << '\n'); } + +} // namespace utils::io + +#endif // TNT_UTILS_OSTREAM_H diff --git a/package/ios/libs/filament/include/utils/unwindows.h b/package/ios/libs/filament/include/utils/unwindows.h new file mode 100644 index 00000000..328ba4dd --- /dev/null +++ b/package/ios/libs/filament/include/utils/unwindows.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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. + */ + +#if defined (WIN32) + +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#ifdef far +#undef far +#endif + +#ifdef near +#undef near +#endif + +#ifdef ERROR +#undef ERROR +#endif + +#ifdef OPAQUE +#undef OPAQUE +#endif + +#ifdef TRANSPARENT +#undef TRANSPARENT +#endif + +#ifdef PURE +#undef PURE +#endif + +#endif diff --git a/package/ios/libs/filament/include/viewer/AutomationEngine.h b/package/ios/libs/filament/include/viewer/AutomationEngine.h new file mode 100644 index 00000000..8747f59d --- /dev/null +++ b/package/ios/libs/filament/include/viewer/AutomationEngine.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_AUTOMATION_ENGINE_H +#define VIEWER_AUTOMATION_ENGINE_H + +#include + +namespace filament { + +class ColorGrading; +class Engine; +class LightManager; +class MaterialInstance; +class Renderer; +class View; + +namespace viewer { + +/** + * The AutomationEngine makes it easy to push a bag of settings values to Filament. + * It can also be used to iterate through settings permutations for testing purposes. + * + * When creating an automation engine for testing purposes, clients give it an immutable reference + * to an AutomationSpec. It is always in one of two states: running or idle. The running state can + * be entered immediately (startRunning) or by requesting batch mode (startBatchMode). + * + * When executing a test, clients should call tick() after each frame is rendered, which gives + * automation an opportunity to push settings to Filament, increment the current test index (if + * enough time has elapsed), and request an asynchronous screenshot. + * + * The time to sleep between tests is configurable and can be set to zero. Automation also waits a + * specified minimum number of frames between tests. + * + * Batch mode is meant for non-interactive applications. In batch mode, automation defers applying + * the first test case until the client unblocks it via signalBatchMode(). This is useful when + * waiting for a large model file to become fully loaded. Batch mode also offers a query + * (shouldClose) that is triggered after the last test has been invoked. + */ +class UTILS_PUBLIC AutomationEngine { +public: + /** + * Allows users to toggle screenshots, change the sleep duration between tests, etc. + */ + struct Options { + /** + * Minimum time that automation waits between applying a settings object and advancing + * to the next test case. Specified in seconds. + */ + float sleepDuration = 0.2f; + + /** + * Similar to sleepDuration, but expressed as a frame count. Both the minimum sleep time + * and the minimum frame count must be elapsed before automation advances to the next test. + */ + int minFrameCount = 2; + + /** + * If true, test progress is dumped to the utils Log (info priority). + */ + bool verbose = true; + + /** + * If true, the tick function writes out a screenshot before advancing to the next test. + */ + bool exportScreenshots = false; + + /** + * If true, the tick function writes out a settings JSON file before advancing. + */ + bool exportSettings = false; + }; + + /** + * Collection of Filament objects that can be modified by the automation engine. + */ + struct ViewerContent { + View* view; + Renderer* renderer; + MaterialInstance* const* materials; + size_t materialCount; + LightManager* lightManager; + Scene* scene; + IndirectLight* indirectLight; + utils::Entity sunlight; + utils::Entity* assetLights; + size_t assetLightCount; + }; + + /** + * Creates an automation engine and places it in an idle state. + * + * @param spec Specifies a set of settings permutations (owned by the client). + * @param settings Client-owned settings object. This not only supplies the initial + * state, it also receives changes during tick(). This is useful when + * building automation into an application that has a settings UI. + * + * @see setOptions + * @see startRunning + */ + AutomationEngine(const AutomationSpec* spec, Settings* settings) : + mSpec(spec), mSettings(settings) {} + + /** + * Shortcut constructor that creates an automation engine from a JSON string. + * + * This constructor can be used if the user does not need to monitor how the settings + * change over time and does not need ownership over the AutomationSpec. + * + * An example of a JSON spec can be found by searching the repo for DEFAULT_AUTOMATION. + * This is documented using a JSON schema (look for viewer/schemas/automation.json). + * + * @param jsonSpec Valid JSON string that conforms to the automation schema. + * @param size Number of characters in the JSON string. + * @return Automation engine or null if unable to read the JSON. + */ + static AutomationEngine* createFromJSON(const char* jsonSpec, size_t size); + + /** + * Creates an automation engine for the sole purpose of pushing settings, or for executing + * the default test sequence. + * + * To see how the default test sequence is generated, search for DEFAULT_AUTOMATION. + */ + static AutomationEngine* createDefault(); + + /** + * Activates the automation test. During the subsequent call to tick(), the first test is + * applied and automation enters the running state. + */ + void startRunning(); + + /** + * Activates the automation test, but enters a paused state until the user calls + * signalBatchMode(). + */ + void startBatchMode(); + + /** + * Notifies the automation engine that time has passed, a new frame has been rendered. + * + * This is when settings get applied, screenshots are (optionally) exported, and the internal + * test counter is potentially incremented. + * + * @param content Contains the Filament View, Materials, and Renderer that get modified. + * @param deltaTime The amount of time that has passed since the previous tick in seconds. + */ + void tick(Engine* engine, const ViewerContent& content, float deltaTime); + + /** + * Mutates a set of client-owned Filament objects according to a JSON string. + * + * This method is an alternative to tick(). It allows clients to use the automation engine as a + * remote control, as opposed to iterating through a predetermined test sequence. + * + * This updates the stashed Settings object, then pushes those settings to the given + * Filament objects. Clients can optionally call getColorGrading() after calling this method. + * + * @param json Contains the JSON string with a set of changes that need to be pushed. + * @param jsonLength Number of characters in the json string. + * @param content Contains a set of Filament objects that you want to mutate. + */ + void applySettings(Engine* engine, const char* json, size_t jsonLength, const ViewerContent& content); + + /** + * Gets a color grading object that corresponds to the latest settings. + * + * This method either returns a cached instance, or it destroys the cached instance and creates + * a new one. + */ + ColorGrading* getColorGrading(Engine* engine); + + /** + * Gets the current viewer options. + * + * NOTE: Focal length here might be different from the user-specified value, due to DoF options. + */ + ViewerOptions getViewerOptions() const; + + /** + * Signals that batch mode can begin. Call this after all meshes and textures finish loading. + */ + void signalBatchMode() { mBatchModeAllowed = true; } + + /** + * Cancels an in-progress automation session. + */ + void stopRunning() { mIsRunning = false; } + + /** + * Signals that the application is closing, so all pending screenshots should be cancelled. + */ + void terminate(); + + /** + * Configures the automation engine for users who wish to set up a custom sleep time + * between tests, etc. + */ + void setOptions(Options options) { mOptions = options; } + + /** + * Returns true if automation is in batch mode and all tests have finished. + */ + bool shouldClose() const { return mShouldClose; } + + /** + * Convenience function that writes out a JSON file to disk containing all settings. + * + * @param Settings State vector to serialize. + * @param filename Desired JSON filename. + */ + static void exportSettings(const Settings& settings, const char* filename); + + Options getOptions() const { return mOptions; } + bool isRunning() const { return mIsRunning; } + size_t currentTest() const { return mCurrentTest; } + size_t testCount() const { return mSpec->size(); } + bool isBatchModeEnabled() const { return mBatchModeEnabled; } + const char* getStatusMessage() const; + ~AutomationEngine(); + +private: + AutomationSpec const * const mSpec; + Settings * const mSettings; + Options mOptions; + + Engine* mColorGradingEngine = nullptr; + ColorGrading* mColorGrading = nullptr; + ColorGradingSettings mColorGradingSettings = {}; + + size_t mCurrentTest; + float mElapsedTime; + int mElapsedFrames; + bool mIsRunning = false; + bool mBatchModeEnabled = false; + bool mRequestStart = false; + bool mShouldClose = false; + bool mBatchModeAllowed = false; + bool mTerminated = false; + bool mOwnsSettings = false; + +public: + // For internal use from a screenshot callback. + void requestClose() { mShouldClose = true; } + bool isTerminated() const { return mTerminated; } +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_AUTOMATION_ENGINE_H diff --git a/package/ios/libs/filament/include/viewer/AutomationSpec.h b/package/ios/libs/filament/include/viewer/AutomationSpec.h new file mode 100644 index 00000000..49e16854 --- /dev/null +++ b/package/ios/libs/filament/include/viewer/AutomationSpec.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_AUTOMATION_SPEC_H +#define VIEWER_AUTOMATION_SPEC_H + +#include + +#include + +namespace filament { +namespace viewer { + +/** + * Immutable list of Settings objects generated from a JSON spec. + * + * Each top-level item in the JSON spec is an object with "name", "base" and "permute". + * The "base" object specifies a single set of changes to apply to default settings. + * The optional "permute" object specifies a cross product of changes to apply to the base. + * + * The following example generates a total of 5 test cases. + * [{ + * "name": "simple", + * "base": { + * "view.dof.cocScale": 1.0, + * "view.bloom.strength": 0.5 + * }, + * "permute": { + * "view.bloom.enabled": [false, true], + * "view.dof.enabled": [false, true] + * } + * }, + * { + * "name": "ppoff", + * "base": { + * "view.postProcessingEnabled": false + * } + * }] + */ +class UTILS_PUBLIC AutomationSpec { +public: + + // Parses a JSON spec, then generates a list of Settings objects. + // Returns null on failure (see utils log for warnings and errors). + // Clients should release memory using "delete". + static AutomationSpec* generate(const char* jsonSpec, size_t size); + + // Generates a list of Settings objects using an embedded JSON spec. + static AutomationSpec* generateDefaultTestCases(); + + // Returns the number of generated Settings objects. + size_t size() const; + + // Gets a generated Settings object and copies it out. + // Returns false if the given index is out of bounds. + bool get(size_t index, Settings* out) const; + + // Returns the name of the JSON group for a given Settings object. + char const* getName(size_t index) const; + + // Frees all Settings objects and name strings. + ~AutomationSpec(); + +private: + struct Impl; + AutomationSpec(Impl*); + Impl* mImpl; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_AUTOMATION_SPEC_H diff --git a/package/ios/libs/filament/include/viewer/RemoteServer.h b/package/ios/libs/filament/include/viewer/RemoteServer.h new file mode 100644 index 00000000..6272b872 --- /dev/null +++ b/package/ios/libs/filament/include/viewer/RemoteServer.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIEWER_REMOTE_SERVER_H +#define VIEWER_REMOTE_SERVER_H + +#include + +#include + +#include +#include + +class CivetServer; + +namespace filament { +namespace viewer { + +class MessageSender; +class MessageReceiver; + +/** + * Encapsulates a message sent from the web client. + * + * All instances of ReceivedMessage and their data / strings are owned by RemoteServer. + * These can be freed via RemoteServer::releaseReceivedMessage(). + */ +struct ReceivedMessage { + char* label; + char* buffer; + size_t bufferByteCount; + size_t messageUid; +}; + +/** + * Manages a tiny WebSocket server that can receive model data and viewer settings. + * + * Client apps can call peekReceivedMessage to check for new data, or acquireReceivedMessage + * to pop it off the small internal queue. When they are done examining the message contents + * they should call releaseReceivedMessage. + */ +class UTILS_PUBLIC RemoteServer { +public: + RemoteServer(int port = 8082); + ~RemoteServer(); + bool isValid() const { return mMessageSender; } + + /** + * Checks if a download is currently in progress and returns its label. + * Returns null if nothing is being downloaded. + */ + char const* peekIncomingLabel() const; + + /** + * Pops a message off the incoming queue or returns null if there are no unread messages. + * + * After examining its contents, users should free the message with releaseReceivedMessage. + */ + ReceivedMessage const* acquireReceivedMessage(); + + /** + * Frees the memory that holds the contents of a received message. + */ + void releaseReceivedMessage(ReceivedMessage const* message); + + void sendMessage(const Settings& settings); + void sendMessage(const char* label, const char* buffer, size_t bufsize); + + // For internal use (makes JNI simpler) + ReceivedMessage const* peekReceivedMessage() const; + +private: + void enqueueReceivedMessage(ReceivedMessage* message); + void setIncomingMessage(ReceivedMessage* message); + MessageSender* mMessageSender = nullptr; + MessageReceiver* mMessageReceiver = nullptr; + size_t mNextMessageUid = 0; + static const size_t kMessageCapacity = 4; + ReceivedMessage* mReceivedMessages[kMessageCapacity] = {}; + ReceivedMessage* mIncomingMessage = nullptr; + JsonSerializer mSerializer; + mutable std::mutex mReceivedMessagesMutex; + friend class MessageReceiver; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_REMOTE_SERVER_H diff --git a/package/ios/libs/filament/include/viewer/Settings.h b/package/ios/libs/filament/include/viewer/Settings.h new file mode 100644 index 00000000..6682260c --- /dev/null +++ b/package/ios/libs/filament/include/viewer/Settings.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_SETTINGS_H +#define VIEWER_SETTINGS_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +namespace filament { + +using namespace color; + +class Skybox; +class Renderer; + +namespace viewer { + +struct ColorGradingSettings; +struct DynamicLightingSettings; +struct MaterialSettings; +struct Settings; +struct ViewSettings; +struct LightSettings; +struct ViewerOptions; + +enum class ToneMapping : uint8_t { + LINEAR = 0, + ACES_LEGACY = 1, + ACES = 2, + FILMIC = 3, + AGX = 4, + GENERIC = 5, + DISPLAY_RANGE = 6, +}; + +using AmbientOcclusionOptions = filament::View::AmbientOcclusionOptions; +using ScreenSpaceReflectionsOptions = filament::View::ScreenSpaceReflectionsOptions; +using AntiAliasing = filament::View::AntiAliasing; +using BloomOptions = filament::View::BloomOptions; +using DepthOfFieldOptions = filament::View::DepthOfFieldOptions; +using Dithering = filament::View::Dithering; +using FogOptions = filament::View::FogOptions; +using RenderQuality = filament::View::RenderQuality; +using ShadowType = filament::View::ShadowType; +using DynamicResolutionOptions = filament::View::DynamicResolutionOptions; +using MultiSampleAntiAliasingOptions = filament::View::MultiSampleAntiAliasingOptions; +using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions; +using VignetteOptions = filament::View::VignetteOptions; +using VsmShadowOptions = filament::View::VsmShadowOptions; +using GuardBandOptions = filament::View::GuardBandOptions; +using StereoscopicOptions = filament::View::StereoscopicOptions; +using LightManager = filament::LightManager; + +// These functions push all editable property values to their respective Filament objects. +void applySettings(Engine* engine, const ViewSettings& settings, View* dest); +void applySettings(Engine* engine, const MaterialSettings& settings, MaterialInstance* dest); +void applySettings(Engine* engine, const LightSettings& settings, IndirectLight* ibl, utils::Entity sunlight, + const utils::Entity* sceneLights, size_t sceneLightCount, LightManager* lm, Scene* scene, View* view); +void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera, Skybox* skybox, + Renderer* renderer); + +// Creates a new ColorGrading object based on the given settings. +UTILS_PUBLIC +ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine); + +class UTILS_PUBLIC JsonSerializer { +public: + JsonSerializer(); + ~JsonSerializer(); + + // Writes a human-readable JSON string into an internal buffer and returns the result. + const std::string& writeJson(const Settings& in); + + // Reads the given JSON blob and updates the corresponding fields in the given Settings object. + // - The given JSON blob need not specify all settings. + // - Returns true if successful. + // - This function writes warnings and error messages into the utils log. + bool readJson(const char* jsonChunk, size_t size, Settings* out); + +private: + class Context; + Context* context; +}; + +struct GenericToneMapperSettings { + float contrast = 1.55f; + float midGrayIn = 0.18f; + float midGrayOut = 0.215f; + float hdrMax = 10.0f; + bool operator!=(const GenericToneMapperSettings& rhs) const { return !(rhs == *this); } + bool operator==(const GenericToneMapperSettings& rhs) const; +}; + +struct AgxToneMapperSettings { + AgxToneMapper::AgxLook look = AgxToneMapper::AgxLook::NONE; + bool operator!=(const AgxToneMapperSettings& rhs) const { return !(rhs == *this); } + bool operator==(const AgxToneMapperSettings& rhs) const; +}; + +struct ColorGradingSettings { + // fields are ordered to avoid padding + bool enabled = true; + bool linkedCurves = false; + bool luminanceScaling = false; + bool gamutMapping = false; + filament::ColorGrading::QualityLevel quality = filament::ColorGrading::QualityLevel::MEDIUM; + ToneMapping toneMapping = ToneMapping::ACES_LEGACY; + bool padding0{}; + AgxToneMapperSettings agxToneMapper; + color::ColorSpace colorspace = Rec709-sRGB-D65; + GenericToneMapperSettings genericToneMapper; + math::float4 shadows{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 midtones{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 highlights{1.0f, 1.0f, 1.0f, 0.0f}; + math::float4 ranges{0.0f, 0.333f, 0.550f, 1.0f}; + math::float3 outRed{1.0f, 0.0f, 0.0f}; + math::float3 outGreen{0.0f, 1.0f, 0.0f}; + math::float3 outBlue{0.0f, 0.0f, 1.0f}; + math::float3 slope{1.0f}; + math::float3 offset{0.0f}; + math::float3 power{1.0f}; + math::float3 gamma{1.0f}; + math::float3 midPoint{1.0f}; + math::float3 scale{1.0f}; + float exposure = 0.0f; + float nightAdaptation = 0.0f; + float temperature = 0.0f; + float tint = 0.0f; + float contrast = 1.0f; + float vibrance = 1.0f; + float saturation = 1.0f; + + bool operator!=(const ColorGradingSettings &rhs) const { return !(rhs == *this); } + bool operator==(const ColorGradingSettings &rhs) const; +}; + +struct DynamicLightingSettings { + float zLightNear = 5; + float zLightFar = 100; +}; + +struct FogSettings { + Texture* fogColorTexture = nullptr; +}; + +// This defines fields in the same order as the setter methods in filament::View. +struct ViewSettings { + // standalone View settings + AntiAliasing antiAliasing = AntiAliasing::FXAA; + Dithering dithering = Dithering::TEMPORAL; + ShadowType shadowType = ShadowType::PCF; + bool postProcessingEnabled = true; + + // View Options (sorted) + AmbientOcclusionOptions ssao; + ScreenSpaceReflectionsOptions screenSpaceReflections; + BloomOptions bloom; + DepthOfFieldOptions dof; + DynamicResolutionOptions dsr; + FogOptions fog; + MultiSampleAntiAliasingOptions msaa; + RenderQuality renderQuality; + TemporalAntiAliasingOptions taa; + VignetteOptions vignette; + VsmShadowOptions vsmShadowOptions; + GuardBandOptions guardBand; + StereoscopicOptions stereoscopicOptions; + + // Custom View Options + ColorGradingSettings colorGrading; + DynamicLightingSettings dynamicLighting; + FogSettings fogSettings; +}; + +template +struct MaterialProperty { std::string name; T value; }; + +// This struct has a fixed size for simplicity. Each non-empty property name is an override. +struct MaterialSettings { + static constexpr size_t MAX_COUNT = 4; + MaterialProperty scalar[MAX_COUNT]; + MaterialProperty float3[MAX_COUNT]; + MaterialProperty float4[MAX_COUNT]; +}; + +struct LightSettings { + bool enableShadows = true; + bool enableSunlight = true; + LightManager::ShadowOptions shadowOptions; + SoftShadowOptions softShadowOptions; + float sunlightIntensity = 100000.0f; + float sunlightHaloSize = 10.0f; + float sunlightHaloFalloff = 80.0f; + float sunlightAngularRadius = 1.9f; + math::float3 sunlightDirection = {0.6, -1.0, -0.8}; + math::float3 sunlightColor = filament::Color::toLinear({ 0.98, 0.92, 0.89}); + float iblIntensity = 30000.0f; + float iblRotation = 0.0f; +}; + +struct ViewerOptions { + float cameraAperture = 16.0f; + float cameraSpeed = 125.0f; + float cameraISO = 100.0f; + float cameraNear = 0.1f; + float cameraFar = 100.0f; + float cameraEyeOcularDistance = 0.0f; + float cameraEyeToeIn = 0.0f; + float groundShadowStrength = 0.75f; + bool groundPlaneEnabled = false; + bool skyboxEnabled = true; + sRGBColor backgroundColor = { 0.0f }; + float cameraFocalLength = 28.0f; + float cameraFocusDistance = 10.0f; + bool autoScaleEnabled = true; + bool autoInstancingEnabled = false; +}; + +struct Settings { + ViewSettings view; + MaterialSettings material; + LightSettings lighting; + ViewerOptions viewer; +}; + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_SETTINGS_H diff --git a/package/ios/libs/filament/include/viewer/ViewerGui.h b/package/ios/libs/filament/include/viewer/ViewerGui.h new file mode 100644 index 00000000..8f843357 --- /dev/null +++ b/package/ios/libs/filament/include/viewer/ViewerGui.h @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by 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. + */ + +#ifndef VIEWER_VIEWERGUI_H +#define VIEWER_VIEWERGUI_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace filagui { + class ImGuiHelper; +} + +namespace filament { +namespace viewer { + +/** + * \class ViewerGui ViewerGui.h viewer/ViewerGui.h + * \brief Builds ImGui widgets for a simple glTF viewer and manages the associated state. + * + * This is a utility that can be used across multiple platforms, including web. + * + * \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader + * instead. + */ +class UTILS_PUBLIC ViewerGui { +public: + using Animator = gltfio::Animator; + using FilamentAsset = gltfio::FilamentAsset; + using FilamentInstance = gltfio::FilamentInstance; + + static constexpr int DEFAULT_SIDEBAR_WIDTH = 350; + + /** + * Constructs a ViewerGui that has a fixed association with the given Filament objects. + * + * Upon construction, the simple viewer may create some additional Filament objects (such as + * light sources) that it owns. + */ + ViewerGui(Engine* engine, Scene* scene, View* view, + int sidebarWidth = DEFAULT_SIDEBAR_WIDTH); + + /** + * Destroys the ViewerGui and any Filament entities that it owns. + */ + ~ViewerGui(); + + /** + * Sets the viewer's current asset and instance. + * + * The viewer does not claim ownership over the asset or its entities. Clients should use + * AssetLoader and ResourceLoader to load an asset before passing it in. + * + * This method does not add renderables to the scene; see populateScene(). + * + * @param instance The asset to view. + * @param instance The instance to view. + */ + void setAsset(FilamentAsset* asset, FilamentInstance* instance); + + /** + * Adds the asset's ready-to-render entities into the scene. + * + * This is used for asychronous loading. It can be called once per frame to gradually add + * entities into the scene as their textures are loaded. + */ + void populateScene(); + + /** + * Removes the current asset from the viewer. + * + * This removes all the asset entities from the Scene, but does not destroy them. + */ + void removeAsset(); + + /** + * Sets or changes the current scene's IBL to allow the UI manipulate it. + */ + void setIndirectLight(IndirectLight* ibl, math::float3 const* sh3); + + /** + * Applies the currently-selected glTF animation to the transformation hierarchy and updates + * the bone matrices on all renderables. + * + * If an instance is provided, animation is applied to it rather than the "set" instance. + */ + void applyAnimation(double currentTime, FilamentInstance* instance = nullptr); + + /** + * Constructs ImGui controls for the current frame and responds to everything that the user has + * changed since the previous frame. + * + * If desired this can be used in conjunction with the filagui library, which allows clients to + * render ImGui controls with Filament. + */ + void updateUserInterface(); + + /** + * Alternative to updateUserInterface that uses an internal instance of ImGuiHelper. + * + * This utility method is designed for clients that do not want to manage their own instance of + * ImGuiHelper (e.g., JavaScript clients). + * + * Behind the scenes this simply calls ImGuiHelper->render() and passes updateUserInterface into + * its callback. Note that the first call might be slower since it requires the creation of the + * internal ImGuiHelper instance. + */ + void renderUserInterface(float timeStepInSeconds, View* guiView, float pixelRatio); + + /** + * Event-passing methods, useful only when ViewerGui manages its own instance of ImGuiHelper. + * The key codes used in these methods are just normal ASCII/ANSI codes. + * @{ + */ + void mouseEvent(float mouseX, float mouseY, bool mouseButton, float mouseWheelY, bool control); + void keyDownEvent(int keyCode); + void keyUpEvent(int keyCode); + void keyPressEvent(int charCode); + /** @}*/ + + /** + * Retrieves the current width of the ImGui "window" which we are using as a sidebar. + * Clients can monitor this value to adjust the size of the view. + */ + int getSidebarWidth() const { return mSidebarWidth; } + + /** + * Allows clients to inject custom UI. + */ + void setUiCallback(std::function callback) { mCustomUI = callback; } + + /** + * Draws the bounding box of each renderable. + * Defaults to false. + */ + void enableWireframe(bool b) { mEnableWireframe = b; } + + /** + * Enables a built-in light source (useful for creating shadows). + * Defaults to true. + */ + void enableSunlight(bool b) { mSettings.lighting.enableSunlight = b; } + + /** + * Enables dithering on the view. + * Defaults to true. + */ + void enableDithering(bool b) { + mSettings.view.dithering = b ? Dithering::TEMPORAL : Dithering::NONE; + } + + /** + * Enables FXAA antialiasing in the post-process pipeline. + * Defaults to true. + */ + void enableFxaa(bool b) { + mSettings.view.antiAliasing = b ? AntiAliasing::FXAA : AntiAliasing::NONE; + } + + /** + * Enables hardware-based MSAA antialiasing. + * Defaults to true. + */ + void enableMsaa(bool b) { + mSettings.view.msaa.sampleCount = 4; + mSettings.view.msaa.enabled = b; + } + + /** + * Enables screen-space ambient occlusion in the post-process pipeline. + * Defaults to true. + */ + void enableSSAO(bool b) { mSettings.view.ssao.enabled = b; } + + /** + * Enables Bloom. + * Defaults to true. + */ + void enableBloom(bool bloom) { mSettings.view.bloom.enabled = bloom; } + + /** + * Adjusts the intensity of the IBL. + * See also IndirectLight::setIntensity(). + * Defaults to 30000.0. + */ + void setIBLIntensity(float brightness) { mSettings.lighting.iblIntensity = brightness; } + + /** + * Updates the transform at the root node according to the autoScaleEnabled setting. + */ + void updateRootTransform(); + + /** + * Gets a modifiable reference to stashed state. + */ + Settings& getSettings() { return mSettings; } + + void stopAnimation() { mCurrentAnimation = -1; } + + int getCurrentCamera() const { return mCurrentCamera; } + +private: + using SceneMask = gltfio::NodeManager::SceneMask; + + bool isRemoteMode() const { return mAsset == nullptr; } + + void sceneSelectionUI(); + + // Immutable properties set from the constructor. + Engine* const mEngine; + Scene* const mScene; + View* const mView; + const utils::Entity mSunlight; + + // Lazily instantiated fields. + filagui::ImGuiHelper* mImGuiHelper = nullptr; + + // Properties that can be changed from the application. + FilamentAsset* mAsset = nullptr; + FilamentInstance* mInstance = nullptr; + IndirectLight* mIndirectLight = nullptr; + std::function mCustomUI; + + // Properties that can be changed from the UI. + int mCurrentAnimation = 0; // -1 means not playing animation and count means plays all of them (0-based index) + int mCurrentVariant = 0; + bool mEnableWireframe = false; + int mVsmMsaaSamplesLog2 = 1; + Settings mSettings; + int mSidebarWidth; + uint32_t mFlags; + utils::Entity mCurrentMorphingEntity; + std::vector mMorphWeights; + SceneMask mVisibleScenes; + bool mShowingRestPose = false; + + // 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 = -1; // zero-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]; + float mCurvePlot[1024 * 3]; +}; + +UTILS_PUBLIC +math::mat4f fitIntoUnitCube(const Aabb& bounds, float zoffset); + +} // namespace viewer +} // namespace filament + +#endif // VIEWER_VIEWERGUI_H diff --git a/package/package.json b/package/package.json index 5488cf7b..22bdb879 100644 --- a/package/package.json +++ b/package/package.json @@ -33,7 +33,7 @@ "prepare": "git submodule update --init --recursive && bob build", "update-submodule": "git submodule update --remote --merge", "build-filament": "scripts/build-filament.sh", - "release": "release-it" + "release": "yarn build-filament && release-it" }, "keywords": [ "react-native",