diff --git a/.github/ISSUE_TEMPLATE/1-bug.yaml b/.github/ISSUE_TEMPLATE/1-bug.yaml new file mode 100644 index 000000000..2e2c65485 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug.yaml @@ -0,0 +1,42 @@ +name: Bug Report +description: File a bug report. +title: "[Bug]: " +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! Please attach any minimal reproduction projects! + - type: textarea + id: description-area + attributes: + label: Description + description: Please provide a description of the bug and what you expected to happen. + validations: + required: true + - type: textarea + id: steps-area + attributes: + label: Steps to reproduce + description: Please provide reproduction steps if possible. + validations: + required: true + - type: dropdown + id: version + attributes: + label: Version + description: What version of Flax are you running? + options: + - '1.8' + - '1.9' + - '1.10' + - '1.11' + - master branch + default: 2 + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant logs + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.yaml b/.github/ISSUE_TEMPLATE/2-feature-request.yaml new file mode 100644 index 000000000..338c9aea0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature-request.yaml @@ -0,0 +1,22 @@ +name: Feature Request +description: File a feature request. +title: "[Request]: " +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out a feature request! + - type: textarea + id: description-area + attributes: + label: Description + description: Please provide a description of the feature! + validations: + required: true + - type: textarea + id: benefits-area + attributes: + label: Benefits + description: Please provide what benefits this feature would provide to the engine! + validations: + required: true \ No newline at end of file diff --git a/Content/Editor/Camera/M_Camera.flax b/Content/Editor/Camera/M_Camera.flax index 5012b16e9..7d7213a8d 100644 --- a/Content/Editor/Camera/M_Camera.flax +++ b/Content/Editor/Camera/M_Camera.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a2936be1789e6a7c663f84ddfea8c897fe8273cd2d29910ac37720907d7b930 +oid sha256:7edc1b9d2c7fbd32fcf778814deb719c71781f657da050ac0c7c78984aeb360d size 29533 diff --git a/Content/Editor/CubeTexturePreviewMaterial.flax b/Content/Editor/CubeTexturePreviewMaterial.flax index 973a01177..5969c90fa 100644 --- a/Content/Editor/CubeTexturePreviewMaterial.flax +++ b/Content/Editor/CubeTexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ecf44ea82025d0f491c68b0470e1704ca5f385bd54ad196d6912aeb2f3aee0f -size 31125 +oid sha256:ac6023e5d6525c3b7c385a380ed9d6fc71ec9d683c587391d14c9daf6653e31a +size 31445 diff --git a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax index 39677f815..fc45d33cc 100644 --- a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax +++ b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d317dc7b2fc2700b28e4a2581c567b888ea1ebb62c5da84f826d9b29c510ff17 -size 40805 +oid sha256:ecd573c40f534f293d4827b1a8150d439d4f5e7729552474926208c5814f3d3e +size 41149 diff --git a/Content/Editor/DebugMaterials/SingleColor/Decal.flax b/Content/Editor/DebugMaterials/SingleColor/Decal.flax index 6024d3961..05e99be76 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Decal.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Decal.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8301da35f0b45f58f5c59221bd22bf0a8500555d31ab84ec1c8cd5eca9fc101 -size 9973 +oid sha256:c0b2ad25738c2bc55bb3e76fc94fc81992b1d65b8b3091b132c75b2ed064c517 +size 10398 diff --git a/Content/Editor/DebugMaterials/SingleColor/Particle.flax b/Content/Editor/DebugMaterials/SingleColor/Particle.flax index 9c2c0755a..7a328e7a0 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Particle.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Particle.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e432328bb19eaa58caf35f60cd6495a46cca694314828010f3be401d7de9434 -size 32108 +oid sha256:02ddea5bcb3fccb697081e47cc26a0b546b23b89ceca299e702a1d431775dfd6 +size 33503 diff --git a/Content/Editor/DebugMaterials/SingleColor/Surface.flax b/Content/Editor/DebugMaterials/SingleColor/Surface.flax index 0fb0d1c6f..84e05ee36 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Surface.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Surface.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1688861997cc2e8a433cdea81ee62662f45b261bc863cdb9431beed612f0aad7 -size 29306 +oid sha256:741a7619b5aebc6c7c6a573a0407e8b7aa42d1b50d0ed5cf6a21026932807d0e +size 29398 diff --git a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax index e5bda89f6..ab4591176 100644 --- a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax +++ b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42363fad30e29b0e0c4cf7ad9e02dc91040eb6821c3c28bd49996771e65893c4 -size 31559 +oid sha256:358370943d21a97f8b45ff2181b7c6c2d7a6297e3f166ae7a77363aadf89b152 +size 32954 diff --git a/Content/Editor/DebugMaterials/SingleColor/Terrain.flax b/Content/Editor/DebugMaterials/SingleColor/Terrain.flax index 09a253a8d..54151179a 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Terrain.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Terrain.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb957ea2ee358b0e611d6612703261c9837099b6d03d48484cdab1151a461d8f -size 21004 +oid sha256:486b4db3e1d825d026753d944a04defe4d72eb73eb03a438944c366f19de824e +size 21096 diff --git a/Content/Editor/DefaultFontMaterial.flax b/Content/Editor/DefaultFontMaterial.flax index b4f659e34..8d48c5827 100644 --- a/Content/Editor/DefaultFontMaterial.flax +++ b/Content/Editor/DefaultFontMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a46410b49a7e38c4c2569e4d8d8c8f4744cf26f79c632a53899ce753ab7c88a +oid sha256:ebdfc478caabc84a3a75384a64d262d2d509bbac3540eea462e45911719c288f size 29627 diff --git a/Content/Editor/Gizmo/FoliageBrushMaterial.flax b/Content/Editor/Gizmo/FoliageBrushMaterial.flax index 1d8e89a65..79385ada6 100644 --- a/Content/Editor/Gizmo/FoliageBrushMaterial.flax +++ b/Content/Editor/Gizmo/FoliageBrushMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f377cc4e05d89e4edbec6382a052abe571f3261bc273cd4475541b7b7051cffb -size 37586 +oid sha256:aa4f1a733150c62064cac60c07980df7c84bb6163dc9507782aa98df07f48874 +size 39637 diff --git a/Content/Editor/Gizmo/Material.flax b/Content/Editor/Gizmo/Material.flax index cce270410..ace3bde90 100644 --- a/Content/Editor/Gizmo/Material.flax +++ b/Content/Editor/Gizmo/Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:271c80d9d9971d96d6ea430dfaf8f8f57d9b5f9fe1770b387f426d3c8721c3d8 -size 32713 +oid sha256:26e1832496c01cb31bd4dc9000d3cd326ea4fd54de02910d3801d2641bff685c +size 34240 diff --git a/Content/Editor/Gizmo/MaterialAxisLocked.flax b/Content/Editor/Gizmo/MaterialAxisLocked.flax deleted file mode 100644 index be44ece86..000000000 --- a/Content/Editor/Gizmo/MaterialAxisLocked.flax +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7518765847301a4b13625fb05d542fab4fc924190a7414d39227db817a0e29cb -size 661 diff --git a/Content/Editor/Gizmo/MaterialWire.flax b/Content/Editor/Gizmo/MaterialWire.flax index 4b30df5f5..7ea0a596f 100644 --- a/Content/Editor/Gizmo/MaterialWire.flax +++ b/Content/Editor/Gizmo/MaterialWire.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff3e7b3e77afa7191f1db9cf12f21908b80bb8f71e832c37e55547dc9dcab31c -size 31410 +oid sha256:ca8bc1ac9d45534d3efd3b4308d7492fa016726b4ec744be26619069ce911b73 +size 32689 diff --git a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax index 962179da0..0c1461b72 100644 --- a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax +++ b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc2facc8fa980e5baa399fa7510a87d33d21bbd4c97eaab24856f6db49b13172 -size 16212 +oid sha256:09f7dff17af9cd055352e0da534f3466c8efa235c40faf5e56da92c788342f6a +size 17394 diff --git a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax index 305c6a4c2..bd4935d96 100644 --- a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax +++ b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4458a9483e81fb0526cc395f93eeae238f4f91fa5d4889e3196b6530a8f17ec2 -size 30419 +oid sha256:1bc0005c64c561a430a17e4707abc000e06498af968890e2c4e223dc07f07c12 +size 30655 diff --git a/Content/Editor/Highlight Material.flax b/Content/Editor/Highlight Material.flax index e944ae62d..ccecb98aa 100644 --- a/Content/Editor/Highlight Material.flax +++ b/Content/Editor/Highlight Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:391606b1f7563d9a8e414baf6c19f3d99694a28f3f574b7aca64a325294d8e39 -size 30104 +oid sha256:95d172cd12bb3c818fbccf737e78ab282bc8d0880aa8f45af0562850b0eabe4b +size 31616 diff --git a/Content/Editor/Icons/IconsMaterial.flax b/Content/Editor/Icons/IconsMaterial.flax index 320547f9a..b24941463 100644 --- a/Content/Editor/Icons/IconsMaterial.flax +++ b/Content/Editor/Icons/IconsMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7951a44b138e60aa9dee4fdaf000eba8a7faef7b31c2e387f78b4a393d0cd0bc -size 30021 +oid sha256:5ca4baa1419080395dcf2b5757676406288f112754bc3cd2f27610b58d199622 +size 31300 diff --git a/Content/Editor/IesProfilePreviewMaterial.flax b/Content/Editor/IesProfilePreviewMaterial.flax index c7a025108..99bc2662c 100644 --- a/Content/Editor/IesProfilePreviewMaterial.flax +++ b/Content/Editor/IesProfilePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41210c6c490513503f01e8a628d80dd98e58fc0482f9966f9342700118ccd04c -size 20445 +oid sha256:b3b4c61b04d372d2430a7c08dec612af6caa0e57b1cb47ea44d171d729d3f8f8 +size 20443 diff --git a/Content/Editor/MaterialTemplates/Decal.shader b/Content/Editor/MaterialTemplates/Decal.shader index b933fcbb3..c958d8a4a 100644 --- a/Content/Editor/MaterialTemplates/Decal.shader +++ b/Content/Editor/MaterialTemplates/Decal.shader @@ -6,6 +6,7 @@ @3 #include "./Flax/Common.hlsl" +#include "./Flax/Stencil.hlsl" #include "./Flax/MaterialCommon.hlsl" #include "./Flax/GBufferCommon.hlsl" @7 @@ -14,10 +15,13 @@ META_CB_BEGIN(0, Data) float4x4 WorldMatrix; float4x4 InvWorld; float4x4 SvPositionToWorld; +float3 Padding0; +uint RenderLayersMask; @1META_CB_END // Use depth buffer for per-pixel decal layering Texture2D DepthBuffer : register(t0); +Texture2D StencilBuffer : register(t1); // Material shader resources @2 @@ -200,6 +204,14 @@ void PS_Decal( #endif ) { + // Stencil masking + uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy)); + if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0) + { + clip(-1); + return; + } + float2 screenUV = SvPosition.xy * ScreenSize.zw; SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r; diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index 657d990e4..123201d1e 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -27,6 +27,7 @@ TextureCube EnvProbe : register(t__SRV__); TextureCube SkyLightTexture : register(t__SRV__); Buffer ShadowsBuffer : register(t__SRV__); Texture2D ShadowMap : register(t__SRV__); +Texture3D VolumetricFogTexture : register(t__SRV__); @4// Forward Shading: Utilities // Public accessors for lighting data, use them as data binding might change but those methods will remain. LightData GetDirectionalLight() { return DirectionalLight; } @@ -151,7 +152,25 @@ void PS_Forward( #if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT // Calculate exponential height fog - float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z); +#if DIRECTX && FEATURE_LEVEL < FEATURE_LEVEL_SM6 + // TODO: fix D3D11/D3D10 bug with incorrect distance + float fogSceneDistance = distance(materialInput.WorldPosition, ViewPos); +#else + float fogSceneDistance = gBuffer.ViewPos.z; +#endif + float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance); + + if (ExponentialHeightFog.VolumetricFogMaxDistance > 0) + { + // Sample volumetric fog and mix it in + float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw; + float3 viewVector = materialInput.WorldPosition - ViewPos; + float sceneDepth = length(viewVector); + float depthSlice = sceneDepth / ExponentialHeightFog.VolumetricFogMaxDistance; + float3 volumeUV = float3(screenUV, depthSlice); + float4 volumetricFog = VolumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0); + fog = CombineVolumetricFog(fog, volumetricFog); + } // Apply fog to the output color #if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE diff --git a/Content/Editor/MaterialTemplates/GUI.shader b/Content/Editor/MaterialTemplates/GUI.shader index 69b6d3539..22da15796 100644 --- a/Content/Editor/MaterialTemplates/GUI.shader +++ b/Content/Editor/MaterialTemplates/GUI.shader @@ -21,7 +21,7 @@ float4 ViewInfo; float4 ScreenSize; float4 ViewSize; float3 ViewPadding0; -float UnscaledTimeParam; +float ScaledTimeParam; @1META_CB_END // Shader resources diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader index 6f0be21e0..661a8f69b 100644 --- a/Content/Editor/MaterialTemplates/Particle.shader +++ b/Content/Editor/MaterialTemplates/Particle.shader @@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID) materialInput.TBN = output.TBN; materialInput.TwoSidedSign = 1; materialInput.SvPosition = output.Position; - materialInput.PreSkinnedPosition = Position; + materialInput.PreSkinnedPosition = position; materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; materialInput.InstanceOrigin = output.InstanceOrigin; materialInput.InstanceParams = output.InstanceParams; diff --git a/Content/Editor/MaterialTemplates/PostProcess.shader b/Content/Editor/MaterialTemplates/PostProcess.shader index 753ccb253..1ef747ecb 100644 --- a/Content/Editor/MaterialTemplates/PostProcess.shader +++ b/Content/Editor/MaterialTemplates/PostProcess.shader @@ -20,7 +20,7 @@ float4 ScreenSize; float4 TemporalAAJitter; float4x4 InverseViewProjectionMatrix; float3 ViewPadding0; -float UnscaledTimeParam; +float ScaledTimeParam; @1META_CB_END // Shader resources diff --git a/Content/Editor/Particles/Particle Material Color.flax b/Content/Editor/Particles/Particle Material Color.flax index bde834456..19eb7a3c2 100644 --- a/Content/Editor/Particles/Particle Material Color.flax +++ b/Content/Editor/Particles/Particle Material Color.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b600cd725f5550de72d5a2544571ca2c1ea8de1a3d45038bac273d2b6f3b04c2 -size 30429 +oid sha256:6f3b8a7c48c55e33a41f9fe4dbf9b3109b0e734ff154d6cbd3e4101013b01649 +size 31708 diff --git a/Content/Editor/Particles/Smoke Material.flax b/Content/Editor/Particles/Smoke Material.flax index 7a8fdeb1a..527d19842 100644 --- a/Content/Editor/Particles/Smoke Material.flax +++ b/Content/Editor/Particles/Smoke Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96d3865771cfa47ad59e0493c8f1b6e9fd9950593b2b929c91ea2692eca71efd -size 38495 +oid sha256:2275282d4e3b5e012a0bbc93fca0d6ffdad89e5a5f0c289678f70748f2efab56 +size 40655 diff --git a/Content/Editor/SpriteMaterial.flax b/Content/Editor/SpriteMaterial.flax index 876a38a56..d967a4ea4 100644 --- a/Content/Editor/SpriteMaterial.flax +++ b/Content/Editor/SpriteMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d02a6d11ea83ea6c519a1644950750e58433e6a2aea9a2daa646db1d2b0c293 -size 30502 +oid sha256:6f5e82be7efa6489cfdfd1babeb1fbb90507aaff7c04eb5f64a4971adf0a2164 +size 30734 diff --git a/Content/Editor/Terrain/Circle Brush Material.flax b/Content/Editor/Terrain/Circle Brush Material.flax index af191fdaa..6ddc5f3e9 100644 --- a/Content/Editor/Terrain/Circle Brush Material.flax +++ b/Content/Editor/Terrain/Circle Brush Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e9ef5186642a38af8ebb5856a891215686576b23841aabe16b7dde7f2bcb57f -size 27676 +oid sha256:2c7fde7be7d6f9876f9c0db02632c098ab95ade7de57c583d2e495c8ae8665bd +size 28232 diff --git a/Content/Editor/Terrain/Highlight Terrain Material.flax b/Content/Editor/Terrain/Highlight Terrain Material.flax index 14bd86c35..c573eb3ee 100644 --- a/Content/Editor/Terrain/Highlight Terrain Material.flax +++ b/Content/Editor/Terrain/Highlight Terrain Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f1a9524d9bc7ee41df761b9fb34613fc04357377a81836fb28b3ee5a6f2dcf4 +oid sha256:9369a554ea1776154f5e39d4aaed044f928d98f1f5955b7590b0972015b07438 size 21179 diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax index fac30b4f1..2c91f9d8f 100644 --- a/Content/Editor/TexturePreviewMaterial.flax +++ b/Content/Editor/TexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c178081b59417439b2d523486f3c7e4f7f391ff57e5ab5a565aadf3fd31f5488 -size 10744 +oid sha256:4d61f178e72e4d983a919b76368e03c66995ecf50935f6f55b660e34f58755a2 +size 11058 diff --git a/Content/Editor/Wires Debug Material.flax b/Content/Editor/Wires Debug Material.flax index 8fff1a174..308a6230a 100644 --- a/Content/Editor/Wires Debug Material.flax +++ b/Content/Editor/Wires Debug Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c31daed51b38e6aa9eeceaad85498d6ae7079f7b125c6f71f036799278c34e22 -size 30104 +oid sha256:c7a42b1bc5a34f9c47d1aeb773ef26ce470b2d88c2b092828f0fcb439583ef27 +size 31616 diff --git a/Content/Engine/DefaultDeformableMaterial.flax b/Content/Engine/DefaultDeformableMaterial.flax index 8af3db999..a397d1ad8 100644 --- a/Content/Engine/DefaultDeformableMaterial.flax +++ b/Content/Engine/DefaultDeformableMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df767eeb060d058d502271f1cd89581c57ad339cd690cc9c588f9a34cc9344b1 -size 18985 +oid sha256:be21bb7eecd9c774196dbaa89d1b049b108fc0929d648795056c977fe00364ab +size 19582 diff --git a/Content/Engine/DefaultMaterial.flax b/Content/Engine/DefaultMaterial.flax index a253452df..eddcbace8 100644 --- a/Content/Engine/DefaultMaterial.flax +++ b/Content/Engine/DefaultMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b00388390410aabb11f1d9b032361902d2f284daa765d536c8f2a821f659effe -size 31331 +oid sha256:0a8a4ad5e763704263b94a7a7e0cc30ab7b1cd1abcb5ccae2d4c6062a65920df +size 31928 diff --git a/Content/Engine/DefaultRadialMenu.flax b/Content/Engine/DefaultRadialMenu.flax index 2b3d7f0de..60e2ba5f9 100644 --- a/Content/Engine/DefaultRadialMenu.flax +++ b/Content/Engine/DefaultRadialMenu.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b0272c8f2df095e6609f49845a3d329daaf634e0776ca764e4c51596cac60ff -size 20514 +oid sha256:c4151a58e5314937efcd3bdcb9fe0bdd5047b8705931e45e0a4e71a4470e16a0 +size 21700 diff --git a/Content/Engine/DefaultTerrainMaterial.flax b/Content/Engine/DefaultTerrainMaterial.flax index 8d195ab98..b302ade35 100644 --- a/Content/Engine/DefaultTerrainMaterial.flax +++ b/Content/Engine/DefaultTerrainMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a86caeef4de5a84783ba34208701c0f272f3b4b3ff82c64c2553d6aec631e07b -size 23301 +oid sha256:c5cf6924809b9bd7ad3c09722a93f327a0d111676060d136df9c14ab34e8475b +size 23930 diff --git a/Content/Engine/SingleColorMaterial.flax b/Content/Engine/SingleColorMaterial.flax index b6906b930..d6d179150 100644 --- a/Content/Engine/SingleColorMaterial.flax +++ b/Content/Engine/SingleColorMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74d77dbfdf72c9281b0760a266adac7f1eb849f9656ea8da5cd8951f2fab5343 -size 29507 +oid sha256:750f69ce59ef020d2e2186ed6c4bf7aac67ecb1692287e358eaed969fc36381a +size 29615 diff --git a/Content/Engine/SkyboxMaterial.flax b/Content/Engine/SkyboxMaterial.flax index 8faccf8c0..cc369ceee 100644 --- a/Content/Engine/SkyboxMaterial.flax +++ b/Content/Engine/SkyboxMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8149367ccbef36932866e6af53fedf79931f26677db5dfcce71ba33caeff5980 -size 31070 +oid sha256:3eecc9556af6c2a79d39a7e1c52e4019bdccfb43b074eaddd18600a5854dbffe +size 31974 diff --git a/Content/Engine/Textures/PreIntegratedGF.flax b/Content/Engine/Textures/PreIntegratedGF.flax index 97783def3..108c92efb 100644 --- a/Content/Engine/Textures/PreIntegratedGF.flax +++ b/Content/Engine/Textures/PreIntegratedGF.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcaf6ab41c5745842a005284259b9ed8eaec73587d73a9e3d7f39086b78ec0e2 -size 87789 +oid sha256:37d0bdbf79b2499b3251a95ffe60702dab1a26a87849fe35e6e47c73f9b46a5e +size 17359 diff --git a/Content/Shaders/Fog.flax b/Content/Shaders/Fog.flax index 3f934412c..9bce56170 100644 --- a/Content/Shaders/Fog.flax +++ b/Content/Shaders/Fog.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e83f9dbbcf84550de09e7c63bbdd3acc6591cf6ba1bcce2a2699772122ae07f4 -size 2633 +oid sha256:72daf0834367b96cc0732e6b3a5d8944c1048f516a52146bfd47f8ad83c95b4a +size 2590 diff --git a/Content/Shaders/Reflections.flax b/Content/Shaders/Reflections.flax index a4605e048..d5ac73593 100644 --- a/Content/Shaders/Reflections.flax +++ b/Content/Shaders/Reflections.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c99a81c70ccb7e9b2e1e4bc5f271c2fe7b36630489fbb269adfaa34de2cc80 -size 3183 +oid sha256:28c80074ac502d5a931b91089fea7bc0c9d573e0bdd317623577833ff328aa8a +size 3107 diff --git a/Content/Shaders/SSR.flax b/Content/Shaders/SSR.flax index 79085c297..1d5932820 100644 --- a/Content/Shaders/SSR.flax +++ b/Content/Shaders/SSR.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9602d25ef9300636aa23112b3ba3a4f45bf1c4c99b1484a86074da5a787abfc -size 11085 +oid sha256:e1a51391e285346f0a67a75ab03b8262cae02d02dddf0d625a6814a51a3b7394 +size 11007 diff --git a/Content/Shaders/Sky.flax b/Content/Shaders/Sky.flax index 87a5b6b3a..a568db451 100644 --- a/Content/Shaders/Sky.flax +++ b/Content/Shaders/Sky.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28d44ef295d989d49ad4d59d6581eee921bc5fa5237e046d271a433454496388 -size 3463 +oid sha256:8541d1f0590167498f44da231f6de4f2938e15b26a5eb58e27b5067e1c882be8 +size 2252 diff --git a/Flax.flaxproj b/Flax.flaxproj index aa685fd07..900a5aa07 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -4,7 +4,7 @@ "Major": 1, "Minor": 11, "Revision": 0, - "Build": 6800 + "Build": 6801 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.", diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 798f210ef..000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,19 +0,0 @@ - - -**Issue description:** - - - -**Steps to reproduce:** - - - -**Minimal reproduction project:** - - - -**Flax version:** - - diff --git a/Source/Editor/Content/Create/PrefabCreateEntry.cs b/Source/Editor/Content/Create/PrefabCreateEntry.cs index 90cca263d..e9ceaaa68 100644 --- a/Source/Editor/Content/Create/PrefabCreateEntry.cs +++ b/Source/Editor/Content/Create/PrefabCreateEntry.cs @@ -117,7 +117,8 @@ namespace FlaxEditor.Content.Create private static bool IsValid(Type type) { - return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType; + var controlTypes = Editor.Instance.CodeEditing.Controls.Get(); + return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type)); } } diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cs b/Source/Editor/CustomEditors/CustomEditorsUtil.cs index 7d7ef123d..476219960 100644 --- a/Source/Editor/CustomEditors/CustomEditorsUtil.cs +++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cs @@ -87,8 +87,11 @@ namespace FlaxEditor.CustomEditors var targetTypeType = TypeUtils.GetType(targetType); if (canUseRefPicker) { + // TODO: add generic way of CustomEditor for ref pickers (use it on AssetRefEditor/GPUTextureEditor/...) if (typeof(Asset).IsAssignableFrom(targetTypeType)) return new AssetRefEditor(); + if (typeof(GPUTexture).IsAssignableFrom(targetTypeType)) + return new GPUTextureEditor(); if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType)) return new FlaxObjectRefEditor(); } diff --git a/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs b/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs index 1ddc1c144..0b15773b8 100644 --- a/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/AudioSourceEditor.cs @@ -13,6 +13,8 @@ namespace FlaxEditor.CustomEditors.Dedicated public class AudioSourceEditor : ActorEditor { private Label _infoLabel; + private Slider _slider; + private AudioSource.States _slideStartState; /// public override void Initialize(LayoutElementsContainer layout) @@ -28,6 +30,13 @@ namespace FlaxEditor.CustomEditors.Dedicated _infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel.AutoHeight = true; + // Play back slider + var sliderElement = playbackGroup.CustomContainer(); + _slider = sliderElement.CustomControl; + _slider.ThumbSize = new Float2(_slider.ThumbSize.X * 0.5f, _slider.ThumbSize.Y); + _slider.SlidingStart += OnSlidingStart; + _slider.SlidingEnd += OnSlidingEnd; + var grid = playbackGroup.UniformGrid(); var gridControl = grid.CustomControl; gridControl.ClipChildren = false; @@ -40,6 +49,38 @@ namespace FlaxEditor.CustomEditors.Dedicated } } + private void OnSlidingEnd() + { + foreach (var value in Values) + { + if (value is AudioSource audioSource && audioSource.Clip) + { + switch (_slideStartState) + { + case AudioSource.States.Playing: + audioSource.Play(); + break; + case AudioSource.States.Paused: + case AudioSource.States.Stopped: + audioSource.Pause(); + break; + default: break; + } + } + } + } + + private void OnSlidingStart() + { + foreach (var value in Values) + { + if (value is AudioSource audioSource && audioSource.Clip) + { + _slideStartState = audioSource.State; + } + } + } + /// public override void Refresh() { @@ -51,7 +92,29 @@ namespace FlaxEditor.CustomEditors.Dedicated foreach (var value in Values) { if (value is AudioSource audioSource && audioSource.Clip) + { text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n"; + _slider.Maximum = audioSource.Clip.Length; + _slider.Minimum = 0; + if (_slider.IsSliding) + { + if (audioSource.State != AudioSource.States.Playing) + { + // Play to move slider correctly + audioSource.Play(); + audioSource.Time = _slider.Value; + } + else + { + audioSource.Time = _slider.Value; + } + } + else + { + _slider.Value = audioSource.Time; + } + + } } _infoLabel.Text = text; } diff --git a/Source/Editor/CustomEditors/Dedicated/GPUTextureEditor.cs b/Source/Editor/CustomEditors/Dedicated/GPUTextureEditor.cs new file mode 100644 index 000000000..2daa3c0a5 --- /dev/null +++ b/Source/Editor/CustomEditors/Dedicated/GPUTextureEditor.cs @@ -0,0 +1,68 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +using FlaxEditor.GUI.ContextMenu; +using FlaxEngine; +using FlaxEngine.GUI; + +namespace FlaxEditor.CustomEditors.Dedicated +{ + /// + /// Basic editor/viewer for . + /// + [CustomEditor(typeof(GPUTexture)), DefaultEditor] + public class GPUTextureEditor : CustomEditor + { + private Image _image; + + /// + public override DisplayStyle Style => DisplayStyle.Inline; + + /// + public override void Initialize(LayoutElementsContainer layout) + { + _image = new Image + { + Brush = new GPUTextureBrush(), + Size = new Float2(200, 100), + Parent = layout.ContainerControl, + }; + _image.Clicked += OnImageClicked; + } + + private void OnImageClicked(Image image, MouseButton button) + { + var texture = Values[0] as GPUTexture; + if (!texture || button != MouseButton.Right) + return; + var menu = new ContextMenu(); + menu.AddButton("Save...", () => Screenshot.Capture(Values[0] as GPUTexture)); + menu.AddButton("Enlarge", () => _image.Size *= 2); + menu.AddButton("Shrink", () => _image.Size /= 2).Enabled = _image.Height > 32; + var location = image.PointFromScreen(Input.MouseScreenPosition); + menu.Show(image, location); + } + + /// + public override void Refresh() + { + base.Refresh(); + + var texture = Values[0] as GPUTexture; + ((GPUTextureBrush)_image.Brush).Texture = texture; + if (texture) + { + var desc = texture.Description; +#if BUILD_RELEASE + var name = string.Empty; +#else + var name = texture.Name; +#endif + _image.TooltipText = $"{name}\nType: {texture.ResourceType}\nSize: {desc.Width}x{desc.Height}\nFormat: {desc.Format}\nMemory: {Utilities.Utils.FormatBytesCount(texture.MemoryUsage)}"; + } + else + { + _image.TooltipText = "None"; + } + } + } +} diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs index 123c7252a..356ae5ee4 100644 --- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs @@ -36,6 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated { ScriptName = scriptName; TooltipText = "Create a new script"; + DrawHighlights = false; } } @@ -70,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4; _addScriptsButton = new Button { - TooltipText = "Add new scripts to the actor", + TooltipText = "Add new scripts to the actor.", AnchorPreset = AnchorPresets.MiddleCenter, Text = buttonText, Parent = this, @@ -114,7 +115,16 @@ namespace FlaxEditor.CustomEditors.Dedicated cm.TextChanged += text => { if (!IsValidScriptName(text)) + { + // Remove NewScriptItems + List newScriptItems = cm.ItemsPanel.Children.FindAll(c => c is NewScriptItem); + foreach (var item in newScriptItems) + { + cm.ItemsPanel.RemoveChild(item); + } + return; + } if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem)) { // If there are no visible items, that means the search failed so we can find the create script button or create one if it's the first time @@ -876,7 +886,7 @@ namespace FlaxEditor.CustomEditors.Dedicated // Add drag button to the group var scriptDrag = new DragImage { - TooltipText = "Script reference", + TooltipText = "Script reference.", AutoFocus = true, IsScrollable = false, Color = FlaxEngine.GUI.Style.Current.ForegroundGrey, diff --git a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs index a0ee8d3dc..b977dab63 100644 --- a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs @@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors menu.AddButton("Copy", linkedEditor.Copy); var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index)); - b.Enabled = linkedEditor.CanPaste && !Editor._readOnly; + b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize; b = menu.AddButton("Paste", linkedEditor.Paste); b.Enabled = linkedEditor.CanPaste && !Editor._readOnly; @@ -407,7 +407,7 @@ namespace FlaxEditor.CustomEditors.Editors menu.AddButton("Copy", linkedEditor.Copy); var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index)); - b.Enabled = linkedEditor.CanPaste && !Editor._readOnly; + b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize; var paste = menu.AddButton("Paste", linkedEditor.Paste); paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly; @@ -422,7 +422,8 @@ namespace FlaxEditor.CustomEditors.Editors moveDownButton.Enabled = Index + 1 < Editor.Count; } - menu.AddButton("Remove", OnRemoveClicked); + b = menu.AddButton("Remove", OnRemoveClicked); + b.Enabled = !Editor._readOnly && Editor._canResize; menu.Show(panel, location); } diff --git a/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs b/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs index 85efbadc3..09670f1b2 100644 --- a/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs @@ -3,6 +3,7 @@ using System; using FlaxEditor.GUI; using FlaxEditor.Scripting; +using FlaxEngine; using FlaxEngine.Utilities; namespace FlaxEditor.CustomEditors.Editors @@ -81,9 +82,13 @@ namespace FlaxEditor.CustomEditors.Editors private OptionType[] _options; private ScriptType _type; + private Elements.PropertiesListElement _typeItem; private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]); + /// + public override bool RevertValueWithChildren => false; // Always revert value for a whole object + /// public override void Initialize(LayoutElementsContainer layout) { @@ -98,7 +103,8 @@ namespace FlaxEditor.CustomEditors.Editors _type = type; // Type - var typeEditor = layout.ComboBox(TypeComboBoxName, "Type of the object value. Use it to change the object."); + _typeItem = layout.AddPropertyItem(TypeComboBoxName, "Type of the object value. Use it to change the object."); + var typeEditor = _typeItem.ComboBox(); for (int i = 0; i < _options.Length; i++) { typeEditor.ComboBox.AddItem(_options[i].Name); @@ -126,6 +132,8 @@ namespace FlaxEditor.CustomEditors.Editors // Value var values = new CustomValueContainer(type, (instance, index) => instance); + if (Values.HasReferenceValue) + values.SetReferenceValue(Values.ReferenceValue); values.AddRange(Values); var editor = CustomEditorsUtil.CreateEditor(type); var style = editor.Style; @@ -170,6 +178,12 @@ namespace FlaxEditor.CustomEditors.Editors { base.Refresh(); + // Show prefab diff when reference value type is different + var color = Color.Transparent; + if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0]?.GetType() != Values.ReferenceValue?.GetType()) + color = FlaxEngine.GUI.Style.Current.BackgroundSelected; + _typeItem.Labels[0].HighlightStripColor = color; + // Check if type has been modified outside the editor (eg. from code) if (Type != _type) { diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp index 99b7f1522..58739917e 100644 --- a/Source/Editor/Editor.cpp +++ b/Source/Editor/Editor.cpp @@ -268,8 +268,8 @@ bool Editor::CheckProjectUpgrade() // Check if last version was older else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR)) { - LOG(Warning, "The project was opened with the older editor version last time"); - const auto result = MessageBox::Show(TEXT("The project was opened with the older editor version last time. Loading it may modify existing data so older editor version won't open it. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question); + LOG(Warning, "The project was last opened with an older editor version"); + const auto result = MessageBox::Show(TEXT("The project was last opened with an older editor version.\nLoading it may modify existing data, which can result in older editor versions being unable to open it.\n\nDo you want to perform a backup before or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question); if (result == DialogResult::Yes) { if (BackupProject()) @@ -291,8 +291,8 @@ bool Editor::CheckProjectUpgrade() // Check if last version was newer else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR)) { - LOG(Warning, "The project was opened with the newer editor version last time"); - const auto result = MessageBox::Show(TEXT("The project was opened with the newer editor version last time. Loading it may fail and corrupt existing data. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning); + LOG(Warning, "The project was last opened with a newer editor version"); + const auto result = MessageBox::Show(TEXT("The project was last opened with a newer editor version.\nLoading it may fail and corrupt existing data.\n\nDo you want to perform a backup before loading or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning); if (result == DialogResult::Yes) { if (BackupProject()) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 853a6eb7d..85e579ec9 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -51,6 +51,7 @@ namespace FlaxEditor private readonly List _modules = new List(16); private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit; private string _projectToOpen; + private bool _projectIsNew; private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f; private Button _saveNowButton; private Button _cancelSaveButton; @@ -737,11 +738,12 @@ namespace FlaxEditor var procSettings = new CreateProcessSettings { FileName = Platform.ExecutableFilePath, - Arguments = string.Format("-project \"{0}\"", _projectToOpen), + Arguments = string.Format("-project \"{0}\"" + (_projectIsNew ? " -new" : string.Empty), _projectToOpen), ShellExecute = true, WaitForEnd = false, HiddenWindow = false, }; + _projectIsNew = false; _projectToOpen = null; Platform.CreateProcess(ref procSettings); } @@ -790,6 +792,24 @@ namespace FlaxEditor } } + /// + /// Creates the given project. Afterwards closes this project with running editor and opens the given project. + /// + /// The project file path. + public void NewProject(string projectFilePath) + { + if (projectFilePath == null) + { + MessageBox.Show("Missing project"); + return; + } + + // Cache project path and start editor exit (it will open new instance on valid closing) + _projectToOpen = StringUtils.NormalizePath(Path.GetDirectoryName(projectFilePath)); + _projectIsNew = true; + Windows.MainWindow.Close(ClosingReason.User); + } + /// /// Closes this project with running editor and opens the given project. /// diff --git a/Source/Editor/GUI/Input/ColorValueBox.cs b/Source/Editor/GUI/Input/ColorValueBox.cs index e627ec2a2..8af955a46 100644 --- a/Source/Editor/GUI/Input/ColorValueBox.cs +++ b/Source/Editor/GUI/Input/ColorValueBox.cs @@ -129,11 +129,39 @@ namespace FlaxEditor.GUI.Input { base.Draw(); - var style = Style.Current; - var r = new Rectangle(0, 0, Width, Height); + bool isTransparent = _value.A < 1; - Render2D.FillRectangle(r, _value); - Render2D.DrawRectangle(r, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black); + var style = Style.Current; + var fullRect = new Rectangle(0, 0, Width, Height); + var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height); + + if (isTransparent) + { + var alphaRect = new Rectangle(colorRect.Right, 0, Width - colorRect.Right, Height); + + // Draw checkerboard pattern to part of the color value box + Render2D.FillRectangle(alphaRect, Color.White); + var smallRectSize = 7.9f; + var numHor = Mathf.CeilToInt(alphaRect.Width / smallRectSize); + var numVer = Mathf.CeilToInt(alphaRect.Height / smallRectSize); + for (int i = 0; i < numHor; i++) + { + for (int j = 0; j < numVer; j++) + { + if ((i + j) % 2 == 0) + { + var rect = new Rectangle(alphaRect.X + smallRectSize * i, alphaRect.Y + smallRectSize * j, new Float2(smallRectSize)); + Render2D.PushClip(alphaRect); + Render2D.FillRectangle(rect, Color.Gray); + Render2D.PopClip(); + } + } + } + Render2D.FillRectangle(alphaRect, _value); + } + + Render2D.FillRectangle(colorRect, _value with { A = 1 }); + Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black); } /// diff --git a/Source/Editor/GUI/ItemsListContextMenu.cs b/Source/Editor/GUI/ItemsListContextMenu.cs index 8fdf21e4c..033af782f 100644 --- a/Source/Editor/GUI/ItemsListContextMenu.cs +++ b/Source/Editor/GUI/ItemsListContextMenu.cs @@ -51,6 +51,11 @@ namespace FlaxEditor.GUI /// public float SortScore; + /// + /// Wether the query highlights should be draw. + /// + public bool DrawHighlights = true; + /// /// Occurs when items gets clicked by the user. /// @@ -165,7 +170,7 @@ namespace FlaxEditor.GUI Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted); // Draw all highlights - if (_highlights != null) + if (DrawHighlights && _highlights != null) { var color = style.ProgressNormal * 0.6f; for (int i = 0; i < _highlights.Count; i++) diff --git a/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs b/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs index c18c64ac5..f7aba94b3 100644 --- a/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs @@ -10,6 +10,7 @@ using System.Text; using FlaxEditor.GUI.Timeline.Undo; using FlaxEngine; using FlaxEngine.GUI; +using FlaxEngine.Json; using FlaxEngine.Utilities; namespace FlaxEditor.GUI.Timeline.Tracks @@ -54,7 +55,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks var paramTypeName = LoadName(stream); e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName); if (e.EventParamsTypes[i] == null) + { + Editor.LogError($"Unknown type {paramTypeName}."); isInvalid = true; + } } if (isInvalid) @@ -82,7 +86,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks for (int j = 0; j < paramsCount; j++) { stream.Read(dataBuffer, 0, e.EventParamsSizes[j]); - key.Parameters[j] = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j]); + key.Parameters[j] = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j], e.EventParamsSizes[j]); } events[i] = new KeyframesEditor.Keyframe @@ -125,8 +129,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks for (int j = 0; j < paramsCount; j++) { - Marshal.StructureToPtr(key.Parameters[j], ptr, true); - Marshal.Copy(ptr, dataBuffer, 0, e.EventParamsSizes[j]); + Utilities.Utils.StructureToByteArray(key.Parameters[j], e.EventParamsSizes[j], ptr, dataBuffer); stream.Write(dataBuffer, 0, e.EventParamsSizes[j]); } } @@ -153,7 +156,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks /// /// The event key data. /// - public struct EventKey + public struct EventKey : ICloneable { /// /// The parameters values. @@ -178,6 +181,26 @@ namespace FlaxEditor.GUI.Timeline.Tracks sb.Append(')'); return sb.ToString(); } + + /// + public object Clone() + { + if (Parameters == null) + return new EventKey(); + + // Deep clone parameter values (especially boxed value types need to be duplicated to avoid referencing the same ones) + var parameters = new object[Parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + var p = Parameters[i]; + if (p == null || p is FlaxEngine.Object) + parameters[i] = Parameters[i]; + else + parameters[i] = JsonSerializer.Deserialize(JsonSerializer.Serialize(p), p.GetType()); + } + + return new EventKey { Parameters = parameters }; + } } /// @@ -234,6 +257,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks var time = Timeline.CurrentTime; if (!TryGetValue(out var value)) value = Events.Evaluate(time); + value = ((ICloneable)value).Clone(); // Find event at the current location for (int i = Events.Keyframes.Count - 1; i >= 0; i--) diff --git a/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs b/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs index 389041381..32f1575ec 100644 --- a/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs @@ -77,7 +77,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks { var time = stream.ReadSingle(); stream.Read(dataBuffer, 0, e.ValueSize); - var value = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), propertyType); + var value = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), propertyType, e.ValueSize); keyframes[i] = new KeyframesEditor.Keyframe { @@ -142,8 +142,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks for (int i = 0; i < keyframes.Count; i++) { var keyframe = keyframes[i]; - Marshal.StructureToPtr(keyframe.Value, ptr, true); - Marshal.Copy(ptr, dataBuffer, 0, e.ValueSize); + Utilities.Utils.StructureToByteArray(keyframe.Value, e.ValueSize, ptr, dataBuffer); stream.Write(keyframe.Time); stream.Write(dataBuffer); } diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs index bb9684869..03c18268d 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs @@ -1,9 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. using FlaxEditor.Options; -using FlaxEditor.SceneGraph; using FlaxEngine; -using System; namespace FlaxEditor.Gizmo { @@ -21,12 +19,16 @@ namespace FlaxEditor.Gizmo private MaterialInstance _materialAxisY; private MaterialInstance _materialAxisZ; private MaterialInstance _materialAxisFocus; - private MaterialInstance _materialAxisLocked; private MaterialBase _materialSphere; // Material Parameter Names - const String _brightnessParamName = "Brightness"; - const String _opacityParamName = "Opacity"; + private const string _brightnessParamName = "Brightness"; + private const string _opacityParamName = "Opacity"; + + /// + /// Used for example when the selection can't be moved because one actor is static. + /// + private bool _isDisabled; private void InitDrawing() { @@ -42,7 +44,6 @@ namespace FlaxEditor.Gizmo _materialAxisY = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisY"); _materialAxisZ = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisZ"); _materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisFocus"); - _materialAxisLocked = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialAxisLocked"); _materialSphere = FlaxEngine.Content.LoadAsyncInternal("Editor/Gizmo/MaterialSphere"); // Ensure that every asset was loaded @@ -67,17 +68,42 @@ namespace FlaxEditor.Gizmo private void OnEditorOptionsChanged(EditorOptions options) { - float brightness = options.Visual.TransformGizmoBrightness; - _materialAxisX.SetParameterValue(_brightnessParamName, brightness); - _materialAxisY.SetParameterValue(_brightnessParamName, brightness); - _materialAxisZ.SetParameterValue(_brightnessParamName, brightness); - _materialAxisLocked.SetParameterValue(_brightnessParamName, brightness); - + UpdateGizmoBrightness(options); + float opacity = options.Visual.TransformGizmoOpacity; _materialAxisX.SetParameterValue(_opacityParamName, opacity); _materialAxisY.SetParameterValue(_opacityParamName, opacity); _materialAxisZ.SetParameterValue(_opacityParamName, opacity); - _materialAxisLocked.SetParameterValue(_opacityParamName, opacity); + } + + private void UpdateGizmoBrightness(EditorOptions options) + { + _isDisabled = ShouldGizmoBeLocked(); + + float brightness = _isDisabled ? options.Visual.TransformGizmoBrightnessDisabled : options.Visual.TransformGizmoBrightness; + if (Mathf.NearEqual(brightness, (float)_materialAxisX.GetParameterValue(_brightnessParamName))) + return; + _materialAxisX.SetParameterValue(_brightnessParamName, brightness); + _materialAxisY.SetParameterValue(_brightnessParamName, brightness); + _materialAxisZ.SetParameterValue(_brightnessParamName, brightness); + } + + private bool ShouldGizmoBeLocked() + { + bool gizmoLocked = false; + if (Editor.Instance.StateMachine.IsPlayMode && Owner is Viewport.EditorGizmoViewport) + { + // Block editing static scene objects in main view during play mode + foreach (var obj in Editor.Instance.SceneEditing.Selection) + { + if (obj.CanTransform == false) + { + gizmoLocked = true; + break; + } + } + } + return gizmoLocked; } /// @@ -88,20 +114,8 @@ namespace FlaxEditor.Gizmo if (!_modelCube || !_modelCube.IsLoaded) return; - // Find out if any of the selected objects can not be moved - bool gizmoLocked = false; - if (Editor.Instance.StateMachine.IsPlayMode) - { - for (int i = 0; i < SelectionCount; i++) - { - var obj = GetSelectedObject(i); - if (obj.CanTransform == false) - { - gizmoLocked = true; - break; - } - } - } + // Update the gizmo brightness every frame to ensure it updates correctly + UpdateGizmoBrightness(Editor.Instance.Options.Options); // As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order // https://github.com/FlaxEngine/FlaxEngine/issues/680 @@ -136,37 +150,37 @@ namespace FlaxEditor.Gizmo // X axis Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); + MaterialInstance xAxisMaterialTransform = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Y axis Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); + MaterialInstance yAxisMaterialTransform = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Z axis Matrix.RotationX(Mathf.Pi, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); + MaterialInstance zAxisMaterialTransform = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // XY plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX); + MaterialInstance xyPlaneMaterialTransform = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX; cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // ZX plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY); + MaterialInstance zxPlaneMaterialTransform = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisY; cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // YZ plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ); + MaterialInstance yzPlaneMaterialTransform = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Center sphere @@ -186,17 +200,17 @@ namespace FlaxEditor.Gizmo // X axis Matrix.RotationZ(Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); + MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Y axis - MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); + MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Z axis Matrix.RotationX(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); + MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Center box @@ -216,37 +230,37 @@ namespace FlaxEditor.Gizmo // X axis Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref mx1, out m3); - MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); + MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Y axis Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); + MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Z axis Matrix.RotationX(Mathf.Pi, out m2); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); + MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // XY plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX); + MaterialInstance xyPlaneMaterialScale = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX; cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // ZX plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ); + MaterialInstance zxPlaneMaterialScale = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // YZ plane m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); Matrix.Multiply(ref m2, ref m1, out m3); - MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY); + MaterialInstance yzPlaneMaterialScale = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisY; cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); // Center box diff --git a/Source/Editor/Gizmo/UIEditorGizmo.cs b/Source/Editor/Gizmo/UIEditorGizmo.cs index bdc1c56ca..765893bed 100644 --- a/Source/Editor/Gizmo/UIEditorGizmo.cs +++ b/Source/Editor/Gizmo/UIEditorGizmo.cs @@ -155,6 +155,16 @@ namespace FlaxEditor private List _widgets; private Widget _activeWidget; + /// + /// Sets the view size. + /// + /// The new size. + public void SetViewSize(Float2 size) + { + _view.Size = size; + _view.PerformLayout(); + } + /// /// True if enable displaying UI editing background and grid elements. /// diff --git a/Source/Editor/Modules/SceneEditingModule.cs b/Source/Editor/Modules/SceneEditingModule.cs index 11ab2fcb3..c36866bc3 100644 --- a/Source/Editor/Modules/SceneEditingModule.cs +++ b/Source/Editor/Modules/SceneEditingModule.cs @@ -673,6 +673,7 @@ namespace FlaxEditor.Modules pasteAction.Do(out _, out var nodeParents); // Select spawned objects (parents only) + newSelection.Clear(); newSelection.AddRange(nodeParents); var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo); selectAction.Do(); diff --git a/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs b/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs index 5aba20b65..a2a333805 100644 --- a/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs +++ b/Source/Editor/Modules/SourceCodeEditing/InBuildSourceCodeEditor.cs @@ -54,6 +54,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing case CodeEditorTypes.VS2022: Name = "Visual Studio 2022"; break; + case CodeEditorTypes.VS2026: + Name = "Visual Studio 2026"; + break; case CodeEditorTypes.VSCode: Name = "Visual Studio Code"; break; @@ -110,6 +113,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing case CodeEditorTypes.VS2017: case CodeEditorTypes.VS2019: case CodeEditorTypes.VS2022: + case CodeEditorTypes.VS2026: // TODO: finish dynamic files adding to the project //Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync(); break; diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs index cae120ab6..f581af81e 100644 --- a/Source/Editor/Modules/UIModule.cs +++ b/Source/Editor/Modules/UIModule.cs @@ -70,6 +70,53 @@ namespace FlaxEditor.Modules private bool _progressFailed; ContextMenuSingleSelectGroup _numberOfClientsGroup = new ContextMenuSingleSelectGroup(); + + /// + /// Defines a viewport scaling option. + /// + public class ViewportScaleOption + { + /// + /// Defines the viewport scale type. + /// + public enum ViewportScaleType + { + /// + /// Resolution. + /// + Resolution = 0, + + /// + /// Aspect Ratio. + /// + Aspect = 1, + } + + /// + /// The name. + /// + public string Label; + + /// + /// The Type of scaling to do. + /// + public ViewportScaleType ScaleType; + + /// + /// The width and height to scale by. + /// + public Int2 Size; + } + + /// + /// The default viewport scaling options. + /// + public List DefaultViewportScaleOptions = new List(); + + /// + /// The user defined viewport scaling options. + /// + public List CustomViewportScaleOptions = new List(); private ContextMenuButton _menuFileSaveScenes; private ContextMenuButton _menuFileReloadScenes; @@ -409,6 +456,8 @@ namespace FlaxEditor.Modules // Update window background mainWindow.BackgroundColor = Style.Current.Background; + + InitViewportScaleOptions(); InitSharedMenus(); InitMainMenu(mainWindow); @@ -422,6 +471,57 @@ namespace FlaxEditor.Modules mainWindow.PerformLayout(true); } + private void InitViewportScaleOptions() + { + if (DefaultViewportScaleOptions.Count == 0) + { + DefaultViewportScaleOptions.Add(new ViewportScaleOption + { + Label = "Free Aspect", + ScaleType = ViewportScaleOption.ViewportScaleType.Aspect, + Size = new Int2(1, 1), + }); + DefaultViewportScaleOptions.Add(new ViewportScaleOption + { + Label = "16:9 Aspect", + ScaleType = ViewportScaleOption.ViewportScaleType.Aspect, + Size = new Int2(16, 9), + }); + DefaultViewportScaleOptions.Add(new ViewportScaleOption + { + Label = "16:10 Aspect", + ScaleType = ViewportScaleOption.ViewportScaleType.Aspect, + Size = new Int2(16, 10), + }); + DefaultViewportScaleOptions.Add(new ViewportScaleOption + { + Label = "1920x1080 Resolution (Full HD)", + ScaleType = ViewportScaleOption.ViewportScaleType.Resolution, + Size = new Int2(1920, 1080), + }); + DefaultViewportScaleOptions.Add(new ViewportScaleOption + { + Label = "2560x1440 Resolution (2K)", + ScaleType = ViewportScaleOption.ViewportScaleType.Resolution, + Size = new Int2(2560, 1440), + }); + } + + if (Editor.Instance.ProjectCache.TryGetCustomData("CustomViewportScalingOptions", out string data)) + { + CustomViewportScaleOptions = JsonSerializer.Deserialize>(data); + } + } + + /// + /// Saves the custom viewport scaling options. + /// + public void SaveCustomViewportScalingOptions() + { + var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions); + Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions); + } + /// public override void OnUpdate() { @@ -546,6 +646,7 @@ namespace FlaxEditor.Modules _menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync); _menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile); cm.AddSeparator(); + cm.AddButton("New project", NewProject); cm.AddButton("Open project...", OpenProject); cm.AddButton("Reload project", ReloadProject); cm.AddButton("Open project folder", () => FileSystem.ShowFileExplorer(Editor.Instance.GameProject.ProjectFolderPath)); @@ -576,7 +677,7 @@ namespace FlaxEditor.Modules if (item != null) Editor.ContentEditing.Open(item); }); - cm.AddButton("Editor Options", () => Editor.Windows.EditorOptionsWin.Show()); + cm.AddButton("Editor Options", inputOptions.EditorOptionsWindow, () => Editor.Windows.EditorOptionsWin.Show()); // Scene MenuScene = MainMenu.AddButton("Scene"); @@ -851,6 +952,17 @@ namespace FlaxEditor.Modules MasterPanel.Offsets = new Margin(0, 0, ToolStrip.Bottom, StatusBar.Height); } + private void NewProject() + { + // Ask user to create project file + if (FileSystem.ShowSaveFileDialog(Editor.Windows.MainWindow, null, "Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0", false, "Create project file", out var files)) + return; + if (files != null && files.Length > 0) + { + Editor.NewProject(files[0]); + } + } + private void OpenProject() { // Ask user to select project file @@ -1108,5 +1220,267 @@ namespace FlaxEditor.Modules MenuTools = null; MenuHelp = null; } + + internal void CreateViewportSizingContextMenu(ContextMenu vsMenu, int defaultScaleActiveIndex, int customScaleActiveIndex, bool prefabViewport, Action changeView, Action changeActiveIndices) + { + // Add default viewport sizing options + var defaultOptions = DefaultViewportScaleOptions; + for (int i = 0; i < defaultOptions.Count; i++) + { + var viewportScale = defaultOptions[i]; + if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect) + continue; // Skip aspect ratio types in prefab + var button = vsMenu.AddButton(viewportScale.Label); + button.CloseMenuOnClick = false; + button.Tag = viewportScale; + + // No default index is active + if (defaultScaleActiveIndex == -1) + { + button.Icon = SpriteHandle.Invalid; + } + // This is the active index + else if (defaultScaleActiveIndex == i) + { + button.Icon = Style.Current.CheckBoxTick; + changeView(viewportScale); + } + + button.Clicked += () => + { + if (button.Tag == null) + return; + + // Reset selected icon on all buttons + foreach (var child in vsMenu.Items) + { + if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v) + { + if (cmb == button) + { + button.Icon = Style.Current.CheckBoxTick; + var index = defaultOptions.FindIndex(x => x == v); + changeActiveIndices(index, -1); // Reset custom index because default was chosen + changeView(v); + } + else if (cmb.Icon != SpriteHandle.Invalid) + { + cmb.Icon = SpriteHandle.Invalid; + } + } + } + }; + } + if (defaultOptions.Count != 0) + vsMenu.AddSeparator(); + + // Add custom viewport options + var customOptions = CustomViewportScaleOptions; + for (int i = 0; i < customOptions.Count; i++) + { + var viewportScale = customOptions[i]; + if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect) + continue; // Skip aspect ratio types in prefab + var childCM = vsMenu.AddChildMenu(viewportScale.Label); + childCM.CloseMenuOnClick = false; + childCM.Tag = viewportScale; + + // No custom index is active + if (customScaleActiveIndex == -1) + { + childCM.Icon = SpriteHandle.Invalid; + } + // This is the active index + else if (customScaleActiveIndex == i) + { + childCM.Icon = Style.Current.CheckBoxTick; + changeView(viewportScale); + } + + var applyButton = childCM.ContextMenu.AddButton("Apply"); + applyButton.Tag = childCM.Tag = viewportScale; + applyButton.CloseMenuOnClick = false; + applyButton.Clicked += () => + { + if (childCM.Tag == null) + return; + + // Reset selected icon on all buttons + foreach (var child in vsMenu.Items) + { + if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v) + { + if (child == childCM) + { + childCM.Icon = Style.Current.CheckBoxTick; + var index = customOptions.FindIndex(x => x == v); + changeActiveIndices(-1, index); // Reset default index because custom was chosen + changeView(v); + } + else if (cmb.Icon != SpriteHandle.Invalid) + { + cmb.Icon = SpriteHandle.Invalid; + } + } + } + }; + + var deleteButton = childCM.ContextMenu.AddButton("Delete"); + deleteButton.CloseMenuOnClick = false; + deleteButton.Clicked += () => + { + if (childCM.Tag == null) + return; + + var v = (ViewportScaleOption)childCM.Tag; + if (childCM.Icon != SpriteHandle.Invalid) + { + changeActiveIndices(-1, 0); + changeView(defaultOptions[0]); + } + customOptions.Remove(v); + SaveCustomViewportScalingOptions(); + vsMenu.DisposeAllItems(); + CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices); + vsMenu.PerformLayout(); + }; + } + if (customOptions.Count != 0) + vsMenu.AddSeparator(); + + // Add button + var add = vsMenu.AddButton("Add..."); + add.CloseMenuOnClick = false; + add.Clicked += () => + { + var popup = new ContextMenuBase + { + Size = new Float2(230, 125), + ClipChildren = false, + CullChildren = false, + }; + popup.Show(add, new Float2(add.Width, 0)); + + var nameLabel = new Label + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Text = "Name", + HorizontalAlignment = TextAlignment.Near, + }; + nameLabel.LocalX += 10; + nameLabel.LocalY += 10; + + var nameTextBox = new TextBox + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + IsMultiline = false, + }; + nameTextBox.LocalX += 100; + nameTextBox.LocalY += 10; + + var typeLabel = new Label + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Text = "Type", + HorizontalAlignment = TextAlignment.Near, + }; + typeLabel.LocalX += 10; + typeLabel.LocalY += 35; + + var typeDropdown = new Dropdown + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Items = { "Aspect", "Resolution" }, + SelectedItem = "Aspect", + Visible = !prefabViewport, + Width = nameTextBox.Width + }; + typeDropdown.LocalY += 35; + typeDropdown.LocalX += 100; + + var whLabel = new Label + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Text = "Width & Height", + HorizontalAlignment = TextAlignment.Near, + }; + whLabel.LocalX += 10; + whLabel.LocalY += 60; + + var wValue = new IntValueBox(16) + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + MinValue = 1, + Width = 55, + }; + wValue.LocalY += 60; + wValue.LocalX += 100; + + var hValue = new IntValueBox(9) + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + MinValue = 1, + Width = 55, + }; + hValue.LocalY += 60; + hValue.LocalX += 165; + + var submitButton = new Button + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Text = "Submit", + Width = 70, + }; + submitButton.LocalX += 40; + submitButton.LocalY += 90; + submitButton.Clicked += () => + { + Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleOption.ViewportScaleType type); + if (prefabViewport) + type = ViewportScaleOption.ViewportScaleType.Resolution; + + var combineString = type == ViewportScaleOption.ViewportScaleType.Aspect ? ":" : "x"; + var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem; + var newViewportOption = new ViewportScaleOption + { + ScaleType = type, + Label = name, + Size = new Int2(wValue.Value, hValue.Value), + }; + + customOptions.Add(newViewportOption); + SaveCustomViewportScalingOptions(); + vsMenu.DisposeAllItems(); + CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices); + vsMenu.PerformLayout(); + }; + + var cancelButton = new Button + { + Parent = popup, + AnchorPreset = AnchorPresets.TopLeft, + Text = "Cancel", + Width = 70, + }; + cancelButton.LocalX += 120; + cancelButton.LocalY += 90; + cancelButton.Clicked += () => + { + nameTextBox.Clear(); + typeDropdown.SelectedItem = "Aspect"; + hValue.Value = 9; + wValue.Value = 16; + popup.Hide(); + }; + }; + } } } diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index af919c1f3..ab473ebed 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -650,6 +650,10 @@ namespace FlaxEditor.Options [EditorDisplay("Windows"), EditorOrder(4020)] public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None); + [DefaultValue(typeof(InputBinding), "Control+Comma")] + [EditorDisplay("Windows"), EditorOrder(4030)] + public InputBinding EditorOptionsWindow = new InputBinding(KeyboardKeys.Comma, KeyboardKeys.Control); + #endregion #region Node Editors diff --git a/Source/Editor/Options/ViewportOptions.cs b/Source/Editor/Options/ViewportOptions.cs index 13ab2a8b0..aed633672 100644 --- a/Source/Editor/Options/ViewportOptions.cs +++ b/Source/Editor/Options/ViewportOptions.cs @@ -150,5 +150,26 @@ namespace FlaxEditor.Options [DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")] [EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")] public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f); + + /// + /// Gets or sets the minimum size used for viewport icons. + /// + [DefaultValue(7.0f), Limit(1.0f, 1000.0f, 5.0f)] + [EditorDisplay("Viewport Icons"), EditorOrder(400)] + public float IconsMinimumSize { get; set; } = 7.0f; + + /// + /// Gets or sets the maximum size used for viewport icons. + /// + [DefaultValue(30.0f), Limit(1.0f, 1000.0f, 5.0f)] + [EditorDisplay("Viewport Icons"), EditorOrder(410)] + public float IconsMaximumSize { get; set; } = 30.0f; + + /// + /// Gets or sets the distance towards the camera at which the max icon scale will be applied. Set to 0 to disable scaling the icons based on the distance to the camera. + /// + [DefaultValue(1000.0f), Limit(0.0f, 20000.0f, 5.0f)] + [EditorDisplay("Viewport Icons"), EditorOrder(410)] + public float MaxSizeDistance { get; set; } = 1000.0f; } } diff --git a/Source/Editor/Options/VisualOptions.cs b/Source/Editor/Options/VisualOptions.cs index 3a12dd0c5..e0f0982f4 100644 --- a/Source/Editor/Options/VisualOptions.cs +++ b/Source/Editor/Options/VisualOptions.cs @@ -81,6 +81,13 @@ namespace FlaxEditor.Options [EditorDisplay("Transform Gizmo", "Gizmo Opacity"), EditorOrder(211)] public float TransformGizmoOpacity { get; set; } = 1f; + /// + /// Gets or set a value indicating how bright the transform gizmo is when it is disabled, for example when one of the selected actors is static in play mode. Use a value of 0 to make the gizmo fully gray. Value over 1 will result in the gizmo emitting light. + /// + [DefaultValue(0.25f), Range(0f, 5f)] + [EditorDisplay("Transform Gizmo", "Disabled Gizmo Brightness"), EditorOrder(212)] + public float TransformGizmoBrightnessDisabled { get; set; } = 0.25f; + /// /// Gets or sets a value indicating whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance. /// diff --git a/Source/Editor/Scripting/CodeEditor.h b/Source/Editor/Scripting/CodeEditor.h index 13edd6af1..9cc71977b 100644 --- a/Source/Editor/Scripting/CodeEditor.h +++ b/Source/Editor/Scripting/CodeEditor.h @@ -62,6 +62,11 @@ API_ENUM(Namespace="FlaxEditor", Attributes="HideInEditor") enum class CodeEdito /// VS2022, + /// + /// Visual Studio 2026 + /// + VS2026, + /// /// Visual Studio Code /// diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp index cebdc681d..5c06eec9c 100644 --- a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp +++ b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.cpp @@ -43,6 +43,9 @@ VisualStudioEditor::VisualStudioEditor(VisualStudioVersion version, const String case VisualStudioVersion::VS2022: _type = CodeEditorTypes::VS2022; break; + case VisualStudioVersion::VS2026: + _type = CodeEditorTypes::VS2026; + break; default: CRASH; break; } @@ -70,6 +73,9 @@ void VisualStudioEditor::FindEditors(Array* output) VisualStudioVersion version; switch (info.VersionMajor) { + case 18: + version = VisualStudioVersion::VS2026; + break; case 17: version = VisualStudioVersion::VS2022; break; diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.h b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.h index 78f069897..1bf1f1433 100644 --- a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.h +++ b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioEditor.h @@ -10,7 +10,7 @@ /// /// Microsoft Visual Studio version types /// -DECLARE_ENUM_8(VisualStudioVersion, VS2008, VS2010, VS2012, VS2013, VS2015, VS2017, VS2019, VS2022); +DECLARE_ENUM_9(VisualStudioVersion, VS2008, VS2010, VS2012, VS2013, VS2015, VS2017, VS2019, VS2022, VS2026); /// /// Implementation of code editor utility that is using Microsoft Visual Studio. diff --git a/Source/Editor/Surface/AnimGraphSurface.cs b/Source/Editor/Surface/AnimGraphSurface.cs index 40cb1fd9a..237e9d019 100644 --- a/Source/Editor/Surface/AnimGraphSurface.cs +++ b/Source/Editor/Surface/AnimGraphSurface.cs @@ -229,20 +229,20 @@ namespace FlaxEditor.Surface } /// - protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox) + protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List startBoxes) { // Check if show additional nodes in the current surface context if (activeCM != _cmStateMachineMenu) { _nodesCache.Get(activeCM); - base.OnShowPrimaryMenu(activeCM, location, startBox); + base.OnShowPrimaryMenu(activeCM, location, startBoxes); activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; } else { - base.OnShowPrimaryMenu(activeCM, location, startBox); + base.OnShowPrimaryMenu(activeCM, location, startBoxes); } } diff --git a/Source/Editor/Surface/Archetypes/Tools.cs b/Source/Editor/Surface/Archetypes/Tools.cs index 091fbe48f..aacebd189 100644 --- a/Source/Editor/Surface/Archetypes/Tools.cs +++ b/Source/Editor/Surface/Archetypes/Tools.cs @@ -1390,7 +1390,7 @@ namespace FlaxEditor.Surface.Archetypes Elements = new[] { NodeElementArchetype.Factory.Output(0, "Time", typeof(float), 0), - NodeElementArchetype.Factory.Output(1, "Unscaled Time", typeof(float), 1), + NodeElementArchetype.Factory.Output(1, "Scaled Time", typeof(float), 1), } }, new NodeArchetype diff --git a/Source/Editor/Surface/BehaviorTreeSurface.cs b/Source/Editor/Surface/BehaviorTreeSurface.cs index 9adcc9949..cf6d7b19a 100644 --- a/Source/Editor/Surface/BehaviorTreeSurface.cs +++ b/Source/Editor/Surface/BehaviorTreeSurface.cs @@ -101,12 +101,12 @@ namespace FlaxEditor.Surface } /// - protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox) + protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List startBoxes) { activeCM.ShowExpanded = true; _nodesCache.Get(activeCM); - base.OnShowPrimaryMenu(activeCM, location, startBox); + base.OnShowPrimaryMenu(activeCM, location, startBoxes); activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; } diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index 94b411fc2..42c863789 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -24,8 +24,8 @@ namespace FlaxEditor.Surface.ContextMenu /// Visject context menu item clicked delegate. /// /// The item that was clicked - /// The currently user-selected box. Can be null. - public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, Elements.Box selectedBox); + /// The currently user-selected boxes. Can be empty/ null. + public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, List selectedBoxes); /// /// Visject Surface node archetype spawn ability checking delegate. @@ -53,7 +53,7 @@ namespace FlaxEditor.Surface.ContextMenu private Panel _panel1; private VerticalPanel _groupsPanel; private readonly ParameterGetterDelegate _parametersGetter; - private Elements.Box _selectedBox; + private List _selectedBoxes = new List(); private NodeArchetype _parameterGetNodeArchetype; private NodeArchetype _parameterSetNodeArchetype; @@ -411,7 +411,8 @@ namespace FlaxEditor.Surface.ContextMenu if (!IsLayoutLocked) { group.UnlockChildrenRecursive(); - if (_contextSensitiveSearchEnabled && _selectedBox != null) + // TODO: Improve filtering to be based on boxes with the most common things instead of first box + if (_contextSensitiveSearchEnabled && _selectedBoxes[0] != null) UpdateFilters(); else SortGroups(); @@ -425,7 +426,8 @@ namespace FlaxEditor.Surface.ContextMenu } else if (_contextSensitiveSearchEnabled) { - group.EvaluateVisibilityWithBox(_selectedBox); + // TODO: Filtering could be improved here as well + group.EvaluateVisibilityWithBox(_selectedBoxes[0]); } Profiler.EndEvent(); @@ -461,7 +463,7 @@ namespace FlaxEditor.Surface.ContextMenu }; } if (_contextSensitiveSearchEnabled) - group.EvaluateVisibilityWithBox(_selectedBox); + group.EvaluateVisibilityWithBox(_selectedBoxes[0]); group.SortChildren(); if (ShowExpanded) group.Open(false); @@ -474,7 +476,7 @@ namespace FlaxEditor.Surface.ContextMenu if (!isLayoutLocked) { - if (_contextSensitiveSearchEnabled && _selectedBox != null) + if (_contextSensitiveSearchEnabled && _selectedBoxes[0] != null) UpdateFilters(); else SortGroups(); @@ -583,7 +585,7 @@ namespace FlaxEditor.Surface.ContextMenu private void UpdateFilters() { - if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBox == null) + if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes[0] == null) { ResetView(); Profiler.EndEvent(); @@ -592,7 +594,7 @@ namespace FlaxEditor.Surface.ContextMenu // Update groups LockChildrenRecursive(); - var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled ? _selectedBox : null; + var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 ? _selectedBoxes[0] : null; for (int i = 0; i < _groups.Count; i++) { _groups[i].UpdateFilter(_searchBox.Text, contextSensitiveSelectedBox); @@ -640,7 +642,7 @@ namespace FlaxEditor.Surface.ContextMenu public void OnClickItem(VisjectCMItem item) { Hide(); - ItemClicked?.Invoke(item, _selectedBox); + ItemClicked?.Invoke(item, _selectedBoxes); } /// @@ -666,12 +668,12 @@ namespace FlaxEditor.Surface.ContextMenu for (int i = 0; i < _groups.Count; i++) { _groups[i].ResetView(); - if (_contextSensitiveSearchEnabled) - _groups[i].EvaluateVisibilityWithBox(_selectedBox); + if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0) + _groups[i].EvaluateVisibilityWithBox(_selectedBoxes[0]); } UnlockChildrenRecursive(); - if (_contextSensitiveSearchEnabled && _selectedBox != null) + if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null) UpdateFilters(); else SortGroups(); @@ -772,10 +774,10 @@ namespace FlaxEditor.Surface.ContextMenu /// /// Parent control to attach to it. /// Popup menu origin location in parent control coordinates. - /// The currently selected box that the new node will get connected to. Can be null - public void Show(Control parent, Float2 location, Elements.Box startBox) + /// The currently selected boxes that the new node will get connected to. Can be empty/ null + public void Show(Control parent, Float2 location, List startBoxes) { - _selectedBox = startBox; + _selectedBoxes = startBoxes; base.Show(parent, location); } diff --git a/Source/Editor/Surface/Elements/Box.cs b/Source/Editor/Surface/Elements/Box.cs index 16b6b3c16..964b3cc69 100644 --- a/Source/Editor/Surface/Elements/Box.cs +++ b/Source/Editor/Surface/Elements/Box.cs @@ -544,35 +544,39 @@ namespace FlaxEditor.Surface.Elements public override void OnMouseLeave() { if (_originalTooltipText != null) - { TooltipText = _originalTooltipText; - } if (_isMouseDown) { _isMouseDown = false; if (Surface.CanEdit) { - if (!IsOutput && HasSingleConnection) + if (IsOutput && Input.GetKey(KeyboardKeys.Control)) { - var connectedBox = Connections[0]; + List connectedBoxes = new List(Connections); + + for (int i = 0; i < connectedBoxes.Count; i++) + { + BreakConnection(connectedBoxes[i]); + Surface.ConnectingStart(connectedBoxes[i], true); + } + } + else if (!IsOutput && HasSingleConnection) + { + var otherBox = Connections[0]; if (Surface.Undo != null && Surface.Undo.Enabled) { - var action = new ConnectBoxesAction((InputBox)this, (OutputBox)connectedBox, false); - BreakConnection(connectedBox); + var action = new ConnectBoxesAction((InputBox)this, (OutputBox)otherBox, false); + BreakConnection(otherBox); action.End(); Surface.AddBatchedUndoAction(action); Surface.MarkAsEdited(); } else - { - BreakConnection(connectedBox); - } - Surface.ConnectingStart(connectedBox); + BreakConnection(otherBox); + Surface.ConnectingStart(otherBox); } else - { Surface.ConnectingStart(this); - } } } base.OnMouseLeave(); diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 97ecab1d0..e1d7c131f 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -151,6 +151,8 @@ namespace FlaxEditor.Surface /// protected virtual Color FooterColor => GroupArchetype.Color; + private Float2 mouseDownMousePosition; + /// /// Calculates the size of the node including header, footer, and margins. /// @@ -917,7 +919,7 @@ namespace FlaxEditor.Surface /// public override bool OnTestTooltipOverControl(ref Float2 location) { - return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting; + return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsSelecting; } /// @@ -1075,7 +1077,7 @@ namespace FlaxEditor.Surface // Header var headerColor = style.BackgroundHighlighted; - if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting) + if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting) headerColor *= 1.07f; Render2D.FillRectangle(_headerRect, headerColor); Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center); @@ -1083,7 +1085,7 @@ namespace FlaxEditor.Surface // Close button if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit) { - bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting; + bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting; Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey); } @@ -1121,7 +1123,7 @@ namespace FlaxEditor.Surface if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) return true; if (button == MouseButton.Right) - return true; + mouseDownMousePosition = Input.Mouse.Position; return false; } @@ -1133,7 +1135,7 @@ namespace FlaxEditor.Surface return true; // Close/ delete - bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection; + bool canDelete = !Surface.IsConnecting && !Surface.WasSelecting && !Surface.WasMovingSelection; if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) { Surface.Delete(this); @@ -1143,6 +1145,10 @@ namespace FlaxEditor.Surface // Secondary Context Menu if (button == MouseButton.Right) { + float distance = Float2.Distance(mouseDownMousePosition, Input.Mouse.Position); + if (distance > 2.5f) + return true; + if (!IsSelected) Surface.Select(this); var tmp = PointToParent(ref location); diff --git a/Source/Editor/Surface/VisjectSurface.Connecting.cs b/Source/Editor/Surface/VisjectSurface.Connecting.cs index dbc2b7fb5..6f60ca2e2 100644 --- a/Source/Editor/Surface/VisjectSurface.Connecting.cs +++ b/Source/Editor/Surface/VisjectSurface.Connecting.cs @@ -1,6 +1,8 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System.Collections.Generic; using FlaxEditor.Scripting; +using FlaxEditor.Surface.Elements; using FlaxEngine; namespace FlaxEditor.Surface @@ -233,11 +235,15 @@ namespace FlaxEditor.Surface /// Begins connecting surface objects action. /// /// The connection instigator (eg. start box). - public void ConnectingStart(IConnectionInstigator instigator) + /// If the instigator should be added to the list of instigators. + public void ConnectingStart(IConnectionInstigator instigator, bool additive = false) { - if (instigator != null && instigator != _connectionInstigator) + if (instigator != null && instigator != _connectionInstigators) { - _connectionInstigator = instigator; + if (!additive) + _connectionInstigators.Clear(); + + _connectionInstigators.Add(instigator); StartMouseCapture(); } } @@ -257,22 +263,30 @@ namespace FlaxEditor.Surface /// The end object (eg. end box). public void ConnectingEnd(IConnectionInstigator end) { - // Ensure that there was a proper start box - if (_connectionInstigator == null) + // Ensure that there is at least one connection instigator + if (_connectionInstigators.Count == 0) return; - var start = _connectionInstigator; - _connectionInstigator = null; - - // Check if boxes are different and end box is specified - if (start == end || end == null) - return; - - // Connect them - if (start.CanConnectWith(end)) + List instigators = new List(_connectionInstigators); + for (int i = 0; i < instigators.Count; i++) { - start.Connect(end); + var start = instigators[i]; + + // Check if boxes are different and end box is specified + if (start == end || end == null) + return; + + // Properly handle connecting to a socket that already has a connection + if (end is Box e && !e.IsOutput && start is Box s && e.AreConnected(s)) + e.BreakConnection(s); + + // Connect them + if (start.CanConnectWith(end)) + start.Connect(end); } + + // Reset instigator list + _connectionInstigators.Clear(); } } } diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index 2cd46593b..d8dfb8ad3 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -261,10 +261,10 @@ namespace FlaxEditor.Surface /// /// The active context menu to show. /// The display location on the surface control. - /// The start box. - protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox) + /// The start boxes. + protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List startBoxes) { - activeCM.Show(this, location, startBox); + activeCM.Show(this, location, startBoxes); } /// @@ -298,8 +298,10 @@ namespace FlaxEditor.Surface _cmStartPos = location; - // Offset added in case the user doesn't like the box and wants to quickly get rid of it by clicking - OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, _connectionInstigator as Box); + List startBoxes = new List(_connectionInstigators.Where(c => c is Box).Cast()); + + // Position offset added so the user can quickly close the menu by clicking + OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, startBoxes); if (!string.IsNullOrEmpty(input)) { @@ -513,17 +515,15 @@ namespace FlaxEditor.Surface private void OnPrimaryMenuVisibleChanged(Control primaryMenu) { if (!primaryMenu.Visible) - { - _connectionInstigator = null; - } + _connectionInstigators.Clear(); } /// /// Handles Visject CM item click event by spawning the selected item. /// /// The item. - /// The selected box. - protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, Box selectedBox) + /// The selected boxes. + protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, List selectedBoxes) { if (!CanEdit) return; @@ -550,34 +550,36 @@ namespace FlaxEditor.Surface // Auto select new node Select(node); - if (selectedBox != null) + for (int i = 0; i < selectedBoxes.Count; i++) { - Box endBox = null; - foreach (var box in node.GetBoxes().Where(box => box.IsOutput != selectedBox.IsOutput)) + Box currentBox = selectedBoxes[i]; + if (currentBox != null) { - if (selectedBox.IsOutput) + Box endBox = null; + foreach (var box in node.GetBoxes().Where(box => box.IsOutput != currentBox.IsOutput)) { - if (box.CanUseType(selectedBox.CurrentType)) + if (currentBox.IsOutput) { - endBox = box; - break; + if (box.CanUseType(currentBox.CurrentType)) + { + endBox = box; + break; + } } - } - else - { - if (selectedBox.CanUseType(box.CurrentType)) + else { - endBox = box; - break; + if (currentBox.CanUseType(box.CurrentType)) + { + endBox = box; + break; + } } - } - if (endBox == null && selectedBox.CanUseType(box.CurrentType)) - { - endBox = box; + if (endBox == null && currentBox.CanUseType(box.CurrentType)) + endBox = box; } + TryConnect(currentBox, endBox); } - TryConnect(selectedBox, endBox); } } @@ -593,13 +595,8 @@ namespace FlaxEditor.Surface } // If the user is patiently waiting for his box to get connected to the newly created one fulfill his wish! - - _connectionInstigator = startBox; - if (!IsConnecting) - { ConnectingStart(startBox); - } ConnectingEnd(endBox); // Smart-Select next box diff --git a/Source/Editor/Surface/VisjectSurface.Draw.cs b/Source/Editor/Surface/VisjectSurface.Draw.cs index f60c19d21..af5893907 100644 --- a/Source/Editor/Surface/VisjectSurface.Draw.cs +++ b/Source/Editor/Surface/VisjectSurface.Draw.cs @@ -1,5 +1,6 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System.Collections.Generic; using FlaxEditor.Surface.Elements; using FlaxEngine; @@ -126,40 +127,45 @@ namespace FlaxEditor.Surface /// Called only when user is connecting nodes. protected virtual void DrawConnectingLine() { - // Get start position - var startPos = _connectionInstigator.ConnectionOrigin; - - // Check if mouse is over any of box var cmVisible = _activeVisjectCM != null && _activeVisjectCM.Visible; var endPos = cmVisible ? _rootControl.PointFromParent(ref _cmStartPos) : _rootControl.PointFromParent(ref _mousePos); Color lineColor = Style.Colors.Connecting; - if (_lastInstigatorUnderMouse != null && !cmVisible) - { - // Check if can connect objects - bool canConnect = _connectionInstigator.CanConnectWith(_lastInstigatorUnderMouse); - lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid; - endPos = _lastInstigatorUnderMouse.ConnectionOrigin; - } - Float2 actualStartPos = startPos; - Float2 actualEndPos = endPos; - - if (_connectionInstigator is Archetypes.Tools.RerouteNode) + List instigators = new List(_connectionInstigators); + for (int i = 0; i < instigators.Count; i++) { - if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true }) + IConnectionInstigator currentInstigator = instigators[i]; + Float2 currentStartPosition = currentInstigator.ConnectionOrigin; + + // Check if mouse is over any box + if (_lastInstigatorUnderMouse != null && !cmVisible) + { + // Check if can connect objects + bool canConnect = currentInstigator.CanConnectWith(_lastInstigatorUnderMouse); + lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid; + endPos = _lastInstigatorUnderMouse.ConnectionOrigin; + } + + Float2 actualStartPos = currentStartPosition; + Float2 actualEndPos = endPos; + + if (currentInstigator is Archetypes.Tools.RerouteNode) + { + if (endPos.X < currentStartPosition.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true }) + { + actualStartPos = endPos; + actualEndPos = currentStartPosition; + } + } + else if (currentInstigator is Box { IsOutput: false }) { actualStartPos = endPos; - actualEndPos = startPos; + actualEndPos = currentStartPosition; } - } - else if (_connectionInstigator is Box { IsOutput: false }) - { - actualStartPos = endPos; - actualEndPos = startPos; - } - // Draw connection - _connectionInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor); + // Draw connection + currentInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor); + } } /// @@ -226,10 +232,10 @@ namespace FlaxEditor.Surface _rootControl.DrawComments(); // Reset input flags here because this is the closest to Update we have - WasBoxSelecting = IsBoxSelecting; + WasSelecting = IsSelecting; WasMovingSelection = IsMovingSelection; - if (IsBoxSelecting) + if (IsSelecting) { DrawSelection(); } diff --git a/Source/Editor/Surface/VisjectSurface.Formatting.cs b/Source/Editor/Surface/VisjectSurface.Formatting.cs index 39ac58242..e1b9a6777 100644 --- a/Source/Editor/Surface/VisjectSurface.Formatting.cs +++ b/Source/Editor/Surface/VisjectSurface.Formatting.cs @@ -176,10 +176,10 @@ namespace FlaxEditor.Surface if (connectedNodes.Count == 0) return; - for (int i = 0; i < connectedNodes.Count - 1; i++) + for (int i = 0; i < connectedNodes.Count; i++) { SurfaceNode nodeA = connectedNodes[i]; - List connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.IsOutput && b.HasAnyConnection).ToList(); + List connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.HasAnyConnection).ToList(); for (int j = 0; j < connectedOutputBoxes.Count; j++) { diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index 891750fd7..51fd96ad6 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -292,7 +292,7 @@ namespace FlaxEditor.Surface if (_leftMouseDown) { // Connecting - if (_connectionInstigator != null) + if (_connectionInstigators.Count > 0) { } // Moving @@ -462,7 +462,7 @@ namespace FlaxEditor.Surface public override bool OnMouseDown(Float2 location, MouseButton button) { // Check if user is connecting boxes - if (_connectionInstigator != null) + if (_connectionInstigators.Count > 0) return true; // Base @@ -608,7 +608,7 @@ namespace FlaxEditor.Surface _movingNodesDelta = Float2.Zero; } // Connecting - else if (_connectionInstigator != null) + else if (_connectionInstigators.Count > 0) { } // Selecting @@ -680,7 +680,7 @@ namespace FlaxEditor.Surface ShowPrimaryMenu(_cmStartPos); } // Letting go of a connection or right clicking while creating a connection - else if (!_isMovingSelection && _connectionInstigator != null && !IsPrimaryMenuOpened) + else if (!_isMovingSelection && _connectionInstigators.Count > 0 && !IsPrimaryMenuOpened) { _cmStartPos = location; Cursor = CursorType.Default; diff --git a/Source/Editor/Surface/VisjectSurface.Serialization.cs b/Source/Editor/Surface/VisjectSurface.Serialization.cs index e490d1550..5bf7a9e34 100644 --- a/Source/Editor/Surface/VisjectSurface.Serialization.cs +++ b/Source/Editor/Surface/VisjectSurface.Serialization.cs @@ -33,7 +33,7 @@ namespace FlaxEditor.Surface Enabled = false; // Clean data - _connectionInstigator = null; + _connectionInstigators.Clear(); _lastInstigatorUnderMouse = null; var failed = RootContext.Load(); diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index 8cbcb4a21..e3bb94bcc 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -121,7 +121,7 @@ namespace FlaxEditor.Surface /// /// The connection start. /// - protected IConnectionInstigator _connectionInstigator; + protected List _connectionInstigators = new List(); /// /// The last connection instigator under mouse. @@ -232,19 +232,19 @@ namespace FlaxEditor.Surface } /// - /// Gets a value indicating whether user is box selecting nodes. + /// Gets a value indicating whether user is selecting nodes. /// - public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null; + public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigators.Count == 0; /// - /// Gets a value indicating whether user was previously box selecting nodes. + /// Gets a value indicating whether user was previously selecting nodes. /// - public bool WasBoxSelecting { get; private set; } + public bool WasSelecting { get; private set; } /// /// Gets a value indicating whether user is moving selected nodes. /// - public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null; + public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigators.Count == 0; /// /// Gets a value indicating whether user was previously moving selected nodes. @@ -254,7 +254,7 @@ namespace FlaxEditor.Surface /// /// Gets a value indicating whether user is connecting nodes. /// - public bool IsConnecting => _connectionInstigator != null; + public bool IsConnecting => _connectionInstigators.Count > 0; /// /// Gets a value indicating whether the left mouse button is down. diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index 0c11e54ff..2f70ee340 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -212,7 +212,7 @@ namespace FlaxEditor.Surface } /// - protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox) + protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List startBoxes) { // Update nodes for method overrides Profiler.BeginEvent("Overrides"); @@ -268,7 +268,7 @@ namespace FlaxEditor.Surface // Update nodes for invoke methods (async) _nodesCache.Get(activeCM); - base.OnShowPrimaryMenu(activeCM, location, startBox); + base.OnShowPrimaryMenu(activeCM, location, startBoxes); activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; } diff --git a/Source/Editor/Tools/Terrain/TerrainTools.cpp b/Source/Editor/Tools/Terrain/TerrainTools.cpp index 2a17f7960..065f7ffeb 100644 --- a/Source/Editor/Tools/Terrain/TerrainTools.cpp +++ b/Source/Editor/Tools/Terrain/TerrainTools.cpp @@ -149,13 +149,13 @@ bool GetTextureDataForSampling(Texture* texture, TextureDataResult& data, bool h bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches, Texture* heightmap, float heightmapScale, Texture* splatmap1, Texture* splatmap2) { + PROFILE_CPU_NAMED("Terrain.GenerateTerrain"); CHECK_RETURN(terrain && terrain->GetChunkSize() != 0, true); if (numberOfPatches.X < 1 || numberOfPatches.Y < 1) { - LOG(Warning, "Cannot setup terain with no patches."); + LOG(Warning, "Cannot setup terrain with no patches."); return false; } - PROFILE_CPU_NAMED("Terrain.GenerateTerrain"); // Wait for assets to be loaded if (heightmap && heightmap->WaitForLoaded()) @@ -178,7 +178,9 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches terrain->AddPatches(numberOfPatches); // Prepare data - const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; + const int32 heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; + const float heightmapSizeInv = 1.0f / (float)(heightmapSize - 1); + const Float2 uvPerPatch = Float2::One / Float2(numberOfPatches); Array heightmapData; heightmapData.Resize(heightmapSize * heightmapSize); @@ -192,19 +194,17 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches const auto sampler = PixelFormatSampler::Get(dataHeightmap.Format); // Initialize with sub-range of the input heightmap - const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches); - const float heightmapSizeInv = 1.0f / (heightmapSize - 1); for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) { auto patch = terrain->GetPatch(patchIndex); - const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch; + const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch; // Sample heightmap pixels with interpolation to get actual heightmap vertices locations for (int32 z = 0; z < heightmapSize; z++) { for (int32 x = 0; x < heightmapSize; x++) { - const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; + const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; const Color color = sampler->SampleLinear(dataHeightmap.Mip0DataPtr->Get(), uv, dataHeightmap.Mip0Size, dataHeightmap.RowPitch); heightmapData[z * heightmapSize + x] = color.R * heightmapScale; } @@ -230,37 +230,30 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches Texture* splatmaps[2] = { splatmap1, splatmap2 }; Array splatmapData; TextureDataResult data1; - const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches); - const float heightmapSizeInv = 1.0f / (heightmapSize - 1); for (int32 index = 0; index < ARRAY_COUNT(splatmaps); index++) { const auto splatmap = splatmaps[index]; if (!splatmap) continue; - // Prepare data - if (splatmapData.IsEmpty()) - splatmapData.Resize(heightmapSize * heightmapSize); - // Get splatmap data if (GetTextureDataForSampling(splatmap, data1)) return true; const auto sampler = PixelFormatSampler::Get(data1.Format); // Modify heightmap splatmaps with sub-range of the input splatmaps + splatmapData.Resize(heightmapSize * heightmapSize); for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) { auto patch = terrain->GetPatch(patchIndex); - - const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch; + const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch; // Sample splatmap pixels with interpolation to get actual splatmap values for (int32 z = 0; z < heightmapSize; z++) { for (int32 x = 0; x < heightmapSize; x++) { - const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; - + const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; const Color color = sampler->SampleLinear(data1.Mip0DataPtr->Get(), uv, data1.Mip0Size, data1.RowPitch); Color32 layers; @@ -374,63 +367,38 @@ Color32* TerrainTools::GetSplatMapData(Terrain* terrain, const Int2& patchCoord, bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder) { + PROFILE_CPU_NAMED("Terrain.ExportTerrain"); CHECK_RETURN(terrain && terrain->GetPatchesCount() != 0, true); - const auto firstPatch = terrain->GetPatch(0); - - // Calculate texture size - const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; - const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount; // Find size of heightmap in patches + const auto firstPatch = terrain->GetPatch(0); Int2 start(firstPatch->GetX(), firstPatch->GetZ()); Int2 end(start); - for (int32 i = 0; i < terrain->GetPatchesCount(); i++) + for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) { - const int32 x = terrain->GetPatch(i)->GetX(); - const int32 y = terrain->GetPatch(i)->GetZ(); - - if (x < start.X) - start.X = x; - if (y < start.Y) - start.Y = y; - if (x > end.X) - end.X = x; - if (y > end.Y) - end.Y = y; + const auto patch = terrain->GetPatch(patchIndex); + const Int2 pos(patch->GetX(), patch->GetZ()); + start = Int2::Min(start, pos); + end = Int2::Max(end, pos); } const Int2 size = (end + 1) - start; - // Allocate - with space for non-existent patches + // Allocate heightmap for a whole terrain (NumberOfPatches * 4x4 * ChunkSize + 1) + const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1; Array heightmap; - heightmap.Resize(patchVertexCount * size.X * size.Y); - - // Set to any element, where: min < elem < max + heightmap.Resize(heightmapSize.X * heightmapSize.Y); heightmap.SetAll(firstPatch->GetHeightmapData()[0]); - const int32 heightmapWidth = patchEdgeVertexCount * size.X; - - // Fill heightmap with data + // Fill heightmap with data from all patches + const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) { - // Pick a patch const auto patch = terrain->GetPatch(patchIndex); - const float* data = patch->GetHeightmapData(); - - // Beginning of patch - int32 dstIndex = (patch->GetX() - start.X) * patchEdgeVertexCount + - (patch->GetZ() - start.Y) * size.Y * patchVertexCount; - - // Iterate over lines in patch - for (int32 z = 0; z < patchEdgeVertexCount; z++) - { - // Iterate over vertices in line - for (int32 x = 0; x < patchEdgeVertexCount; x++) - { - heightmap[dstIndex + x] = data[z * patchEdgeVertexCount + x]; - } - - dstIndex += heightmapWidth; - } + const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y); + const float* src = patch->GetHeightmapData(); + float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1); + for (int32 row = 0; row < rowSize; row++) + Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float)); } // Interpolate to 16-bit int @@ -438,44 +406,42 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder) maxHeight = minHeight = heightmap[0]; for (int32 i = 1; i < heightmap.Count(); i++) { - float h = heightmap[i]; + float h = heightmap.Get()[i]; if (maxHeight < h) maxHeight = h; else if (minHeight > h) minHeight = h; } - - const float maxValue = 65535.0f; - const float alpha = maxValue / (maxHeight - minHeight); + const float alpha = MAX_uint16 / (maxHeight - minHeight); // Storage for pixel data - Array byteHeightmap(heightmap.Capacity()); - - for (auto& elem : heightmap) + Array byteHeightmap; + byteHeightmap.Resize(heightmap.Count()); + for (int32 i = 0; i < heightmap.Count(); i++) { - byteHeightmap.Add(static_cast(alpha * (elem - minHeight))); + float height = heightmap.Get()[i]; + byteHeightmap.Get()[i] = static_cast(alpha * (height - minHeight)); } // Create texture TextureData textureData; - textureData.Height = textureData.Width = heightmapWidth; + textureData.Width = heightmapSize.X; + textureData.Height = heightmapSize.Y; textureData.Depth = 1; textureData.Format = PixelFormat::R16_UNorm; textureData.Items.Resize(1); textureData.Items[0].Mips.Resize(1); - - // Fill mip data TextureMipData* srcMip = textureData.GetData(0, 0); srcMip->Data.Link(byteHeightmap.Get()); srcMip->Lines = textureData.Height; - srcMip->RowPitch = textureData.Width * 2; // 2 bytes per pixel for format R16 + srcMip->RowPitch = textureData.Width * sizeof(uint16); srcMip->DepthPitch = srcMip->Lines * srcMip->RowPitch; // Find next non-existing file heightmap file FileSystem::NormalizePath(outputFolder); const String baseFileName(TEXT("heightmap")); String outputPath; - for (int32 i = 0; i < MAX_int32; i++) + for (int32 i = 0; i < 100; i++) { outputPath = outputFolder / baseFileName + StringUtils::ToString(i) + TEXT(".png"); if (!FileSystem::FileExists(outputPath)) diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index 7594bcd22..ea55edc0b 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -212,6 +212,10 @@ namespace FlaxEditor.Utilities if (value is FlaxEngine.Object) return value; + // For custom types use interface + if (value is ICloneable clonable) + return clonable.Clone(); + // For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor if (value != null && (!value.GetType().IsValueType || !value.GetType().IsClass)) { @@ -548,6 +552,26 @@ namespace FlaxEditor.Utilities return arr; } + internal static void StructureToByteArray(object value, int valueSize, IntPtr tempBuffer, byte[] dataBuffer) + { + var valueType = value.GetType(); + if (valueType.IsEnum) + { + var ptr = FlaxEngine.Interop.NativeInterop.ValueTypeUnboxer.GetPointer(value, valueType); + FlaxEngine.Utils.MemoryCopy(tempBuffer, ptr, (ulong)valueSize); + } + else + Marshal.StructureToPtr(value, tempBuffer, true); + Marshal.Copy(tempBuffer, dataBuffer, 0, valueSize); + } + + internal static object ByteArrayToStructure(IntPtr valuePtr, Type valueType, int valueSize) + { + if (valueType.IsEnum) + return FlaxEngine.Interop.NativeInterop.MarshalToManaged(valuePtr, valueType); + return Marshal.PtrToStructure(valuePtr, valueType); + } + internal static unsafe string ReadStr(this BinaryReader stream, int check) { int length = stream.ReadInt32(); diff --git a/Source/Editor/Utilities/ViewportIconsRenderer.cpp b/Source/Editor/Utilities/ViewportIconsRenderer.cpp index 59c980156..26a705970 100644 --- a/Source/Editor/Utilities/ViewportIconsRenderer.cpp +++ b/Source/Editor/Utilities/ViewportIconsRenderer.cpp @@ -66,13 +66,14 @@ public: ViewportIconsRendererService ViewportIconsRendererServiceInstance; float ViewportIconsRenderer::Scale = 1.0f; +Real ViewportIconsRenderer::MinSize = 7.0f; +Real ViewportIconsRenderer::MaxSize = 30.0f; +Real ViewportIconsRenderer::MaxSizeDistance = 1000.0f; void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds) { - constexpr Real minSize = 7.0; - constexpr Real maxSize = 30.0; - Real scale = Math::Square(Vector3::Distance(position, viewPosition) / 1000.0f); - Real radius = minSize + Math::Min(scale, 1.0f) * (maxSize - minSize); + Real scale = Math::Square(Vector3::Distance(position, viewPosition) / MaxSizeDistance); + Real radius = MinSize + Math::Min(scale, 1.0f) * (MaxSize - MinSize); bounds = BoundingSphere(position, radius * Scale); } @@ -88,6 +89,7 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor draw.Flags = StaticFlags::Transform; draw.DrawModes = DrawPass::Forward; draw.PerInstanceRandom = 0; + draw.StencilValue = 0; draw.LODBias = 0; draw.ForcedLOD = -1; draw.SortOrder = 0; diff --git a/Source/Editor/Utilities/ViewportIconsRenderer.h b/Source/Editor/Utilities/ViewportIconsRenderer.h index c7bf7e1c3..a1e1538b8 100644 --- a/Source/Editor/Utilities/ViewportIconsRenderer.h +++ b/Source/Editor/Utilities/ViewportIconsRenderer.h @@ -22,6 +22,21 @@ public: /// API_FIELD() static float Scale; + /// + /// The minimum size of the icons. + /// + API_FIELD() static Real MinSize; + + /// + /// The maximum size of the icons. + /// + API_FIELD() static Real MaxSize; + + /// + /// The distance to the camera at which the icons will be drawn at their maximum size. + /// + API_FIELD() static Real MaxSizeDistance; + /// /// Draws the icons for the actors in the given scene (or actor tree). /// diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 5956de87d..5fb1c4657 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -541,7 +541,7 @@ namespace FlaxEditor.Viewport // Setup options { - Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged; + _editor.Options.OptionsChanged += OnEditorOptionsChanged; SetupViewportOptions(); } @@ -587,7 +587,7 @@ namespace FlaxEditor.Viewport // Camera Settings Menu var cameraCM = new ContextMenu(); - _cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth) + _cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), _editor.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth) { Tag = this, TooltipText = "Camera Settings", @@ -596,7 +596,7 @@ namespace FlaxEditor.Viewport _cameraWidget.Parent = this; // Orthographic/Perspective Mode Widget - _orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true) + _orthographicModeButton = new ViewportWidgetButton(string.Empty, _editor.Icons.CamSpeed32, null, true) { Checked = !_isOrtho, TooltipText = "Toggle Orthographic/Perspective Mode", @@ -869,8 +869,8 @@ namespace FlaxEditor.Viewport { } }); - viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = Editor.Instance.Icons.Rotate32; - viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0)).Icon = Editor.Instance.Icons.Rotate32; + viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = _editor.Icons.Rotate32; + viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0)); viewLayers.AddSeparator(); var layers = LayersAndTagsSettings.GetCurrentLayers(); if (layers != null && layers.Length > 0) @@ -910,8 +910,8 @@ namespace FlaxEditor.Viewport { } }); - viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate32; - viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None).Icon = Editor.Instance.Icons.Rotate32; + viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = _editor.Icons.Rotate32; + viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None); viewFlags.AddSeparator(); for (int i = 0; i < ViewFlagsValues.Length; i++) { @@ -1091,7 +1091,7 @@ namespace FlaxEditor.Viewport /// private void SetupViewportOptions() { - var options = Editor.Instance.Options.Options; + var options = _editor.Options.Options; _minMovementSpeed = options.Viewport.MinMovementSpeed; MovementSpeed = options.Viewport.MovementSpeed; _maxMovementSpeed = options.Viewport.MaxMovementSpeed; @@ -1298,6 +1298,11 @@ namespace FlaxEditor.Viewport _mouseSensitivity = options.Viewport.MouseSensitivity; _maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps; _cameraEasingDegree = options.Viewport.CameraEasingDegree; + + ViewportIconsRenderer.MinSize = options.Viewport.IconsMinimumSize; + ViewportIconsRenderer.MaxSize = options.Viewport.IconsMaximumSize; + ViewportIconsRenderer.MaxSizeDistance = options.Viewport.MaxSizeDistance; + OnCameraMovementProgressChanged(); } @@ -1711,7 +1716,7 @@ namespace FlaxEditor.Viewport // Check if update mouse var size = Size; - var options = Editor.Instance.Options.Options; + var options = _editor.Options.Options; if (_isControllingMouse) { var rmbWheel = false; @@ -1952,7 +1957,7 @@ namespace FlaxEditor.Viewport return true; // Custom input events - return InputActions.Process(Editor.Instance, this, key); + return InputActions.Process(_editor, this, key); } /// @@ -1969,7 +1974,7 @@ namespace FlaxEditor.Viewport base.Draw(); // Add overlay during debugger breakpoint hang - if (Editor.Instance.Simulation.IsDuringBreakpointHang) + if (_editor.Simulation.IsDuringBreakpointHang) { var bounds = new Rectangle(Float2.Zero, Size); Render2D.FillRectangle(bounds, new Color(0.0f, 0.0f, 0.0f, 0.2f)); @@ -1994,7 +1999,7 @@ namespace FlaxEditor.Viewport /// public override void OnDestroy() { - Editor.Instance.Options.OptionsChanged -= OnEditorOptionsChanged; + _editor.Options.OptionsChanged -= OnEditorOptionsChanged; base.OnDestroy(); } diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index b1b86008d..39c126c37 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -6,6 +6,8 @@ using System.Linq; using FlaxEditor.Content; using FlaxEditor.Gizmo; using FlaxEditor.GUI.ContextMenu; +using FlaxEditor.GUI.Input; +using FlaxEditor.Modules; using FlaxEditor.SceneGraph; using FlaxEditor.Scripting; using FlaxEditor.Viewport.Cameras; @@ -13,6 +15,7 @@ using FlaxEditor.Viewport.Previews; using FlaxEditor.Windows.Assets; using FlaxEngine; using FlaxEngine.GUI; +using FlaxEngine.Json; using Utils = FlaxEditor.Utilities.Utils; namespace FlaxEditor.Viewport @@ -70,8 +73,11 @@ namespace FlaxEditor.Viewport private PrefabUIEditorRoot _uiRoot; private bool _showUI = false; - + + private int _defaultScaleActiveIndex = 0; + private int _customScaleActiveIndex = -1; private ContextMenuButton _uiModeButton; + private ContextMenuChildMenu _uiViewOptions; /// /// Event fired when the UI Mode is toggled. @@ -137,6 +143,8 @@ namespace FlaxEditor.Viewport UseAutomaticTaskManagement = defaultFeatures; ShowDefaultSceneActors = defaultFeatures; TintColor = defaultFeatures ? Color.White : Color.Transparent; + if (_uiViewOptions != null) + _uiViewOptions.Visible = _showUI; UIModeToggled?.Invoke(_showUI); } } @@ -210,7 +218,7 @@ namespace FlaxEditor.Viewport _uiParentLink = _uiRoot.UIRoot; // UI mode buton - _uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", (button) => ShowUI = button.Checked); + _uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", button => ShowUI = button.Checked); _uiModeButton.AutoCheck = true; _uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI; @@ -222,6 +230,84 @@ namespace FlaxEditor.Viewport SetUpdate(ref _update, OnUpdate); } + /// + /// Creates the view scaling options. Needs to be called after a Prefab is valid and loaded. + /// + public void CreateViewScalingOptions() + { + if (_uiViewOptions != null) + return; + _uiViewOptions = ViewWidgetButtonMenu.AddChildMenu("UI View Scaling"); + _uiViewOptions.Visible = _showUI; + LoadCustomUIScalingOption(); + Editor.Instance.UI.CreateViewportSizingContextMenu(_uiViewOptions.ContextMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, true, ChangeUIView, (a, b) => + { + _defaultScaleActiveIndex = a; + _customScaleActiveIndex = b; + }); + } + + private void ChangeUIView(UIModule.ViewportScaleOption uiViewScaleOption) + { + _uiRoot.SetViewSize((Float2)uiViewScaleOption.Size); + } + + /// + /// Saves the active ui scaling option. + /// + public void SaveActiveUIScalingOption() + { + var defaultKey = $"{Prefab.ID}:DefaultViewportScalingIndex"; + Editor.Instance.ProjectCache.SetCustomData(defaultKey, _defaultScaleActiveIndex.ToString()); + var customKey = $"{Prefab.ID}:CustomViewportScalingIndex"; + Editor.Instance.ProjectCache.SetCustomData(customKey, _customScaleActiveIndex.ToString()); + } + + private void LoadCustomUIScalingOption() + { + Prefab.WaitForLoaded(); + var defaultKey = $"{Prefab.ID}:DefaultViewportScalingIndex"; + if (Editor.Instance.ProjectCache.TryGetCustomData(defaultKey, out string defaultData)) + { + if (int.TryParse(defaultData, out var index)) + { + var options = Editor.Instance.UI.DefaultViewportScaleOptions; + if (options.Count > index) + { + _defaultScaleActiveIndex = index; + if (index != -1) + ChangeUIView(Editor.Instance.UI.DefaultViewportScaleOptions[index]); + } + // Assume option does not exist anymore so move to default. + else if (index != -1) + { + _defaultScaleActiveIndex = 0; + } + } + } + + var customKey = $"{Prefab.ID}:CustomViewportScalingIndex"; + if (Editor.Instance.ProjectCache.TryGetCustomData(customKey, out string data)) + { + if (int.TryParse(data, out var index)) + { + var options = Editor.Instance.UI.CustomViewportScaleOptions; + if (options.Count > index) + { + _customScaleActiveIndex = index; + if (index != -1) + ChangeUIView(options[index]); + } + // Assume option does not exist anymore so move to default. + else if (index != -1) + { + _defaultScaleActiveIndex = 0; + _customScaleActiveIndex = -1; + } + } + } + } + private void OnUpdate(float deltaTime) { for (int i = 0; i < Gizmos.Count; i++) diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs index 4ee763540..70316e4d9 100644 --- a/Source/Editor/Viewport/Previews/PrefabPreview.cs +++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs @@ -112,8 +112,9 @@ namespace FlaxEditor.Viewport.Previews LinkCanvas(_instance); // Link UI control to the preview + var uiControl = _instance as UIControl; if (_uiControlLinked == null && - _instance is UIControl uiControl && + uiControl != null && uiControl.Control != null && uiControl.Control.Parent == null) { @@ -128,6 +129,12 @@ namespace FlaxEditor.Viewport.Previews _uiControlLinked.Control.Parent = _uiParentLink; _hasUILinked = true; } + + // Use UI mode when root is empty UI Control + if (_uiControlLinked == null && uiControl != null && uiControl.Control == null) + { + _hasUILinked = true; + } } private void LinkCanvas(Actor actor) diff --git a/Source/Editor/Windows/AboutDialog.cs b/Source/Editor/Windows/AboutDialog.cs index 488c6a14d..3971e0ce4 100644 --- a/Source/Editor/Windows/AboutDialog.cs +++ b/Source/Editor/Windows/AboutDialog.cs @@ -97,6 +97,7 @@ namespace FlaxEditor.Windows "Jean-Baptiste Perrier", "Chandler Cox", "Ari Vuollet", + "Vincent Saarmann", }); authors.Sort(); var authorsLabel = new Label(4, topParentControl.Bottom + 20, Width - 8, 70) diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs index 7f17053ac..1d6d827ab 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.cs @@ -371,6 +371,7 @@ namespace FlaxEditor.Windows.Assets else _viewport.SetInitialUIMode(_viewport._hasUILinked); _viewport.UIModeToggled += OnUIModeToggled; + _viewport.CreateViewScalingOptions(); Graph.MainActor = _viewport.Instance; Selection.Clear(); Select(Graph.Main); @@ -567,6 +568,15 @@ namespace FlaxEditor.Windows.Assets Graph.Dispose(); } + /// + protected override void OnClose() + { + // Save current UI view size state. + _viewport.SaveActiveUIScalingOption(); + + base.OnClose(); + } + /// public EditorViewport PresenterViewport => _viewport; diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs index 6d01432ba..03d435efe 100644 --- a/Source/Editor/Windows/EditorWindow.cs +++ b/Source/Editor/Windows/EditorWindow.cs @@ -116,6 +116,11 @@ namespace FlaxEditor.Windows if (InputOptions.WindowShortcutsAvaliable) Editor.Windows.VisualScriptDebuggerWin.FocusOrShow(); }); + InputActions.Add(options => options.EditorOptionsWindow, () => + { + if (InputOptions.WindowShortcutsAvaliable) + Editor.Windows.EditorOptionsWin.FocusOrShow(); + }); // Register Editor.Windows.OnWindowAdd(this); diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index c4547124c..9a68bd216 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -6,6 +6,7 @@ using System.Xml; using FlaxEditor.Gizmo; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; +using FlaxEditor.Modules; using FlaxEditor.Options; using FlaxEngine; using FlaxEngine.GUI; @@ -34,8 +35,8 @@ namespace FlaxEditor.Windows private CursorLockMode _cursorLockMode = CursorLockMode.None; // Viewport scaling variables - private List _defaultViewportScaling = new List(); - private List _customViewportScaling = new List(); + private int _defaultScaleActiveIndex = 0; + private int _customScaleActiveIndex = -1; private float _viewportAspectRatio = 1; private float _windowAspectRatio = 1; private bool _useAspect = false; @@ -246,35 +247,6 @@ namespace FlaxEditor.Windows /// public InterfaceOptions.PlayModeFocus FocusOnPlayOption { get; set; } - private enum ViewportScaleType - { - Resolution = 0, - Aspect = 1, - } - - private class ViewportScaleOptions - { - /// - /// The name. - /// - public string Label; - - /// - /// The Type of scaling to do. - /// - public ViewportScaleType ScaleType; - - /// - /// The width and height to scale by. - /// - public Int2 Size; - - /// - /// If the scaling is active. - /// - public bool Active; - } - private class PlayModeFocusOptions { /// @@ -420,7 +392,7 @@ namespace FlaxEditor.Windows InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand()); } - private void ChangeViewportRatio(ViewportScaleOptions v) + private void ChangeViewportRatio(UIModule.ViewportScaleOption v) { if (v == null) return; @@ -439,11 +411,11 @@ namespace FlaxEditor.Windows { switch (v.ScaleType) { - case ViewportScaleType.Aspect: + case UIModule.ViewportScaleOption.ViewportScaleType.Aspect: _useAspect = true; _freeAspect = false; break; - case ViewportScaleType.Resolution: + case UIModule.ViewportScaleOption.ViewportScaleType.Resolution: _useAspect = false; _freeAspect = false; break; @@ -634,49 +606,12 @@ namespace FlaxEditor.Windows // Viewport aspect ratio { - // Create default scaling options if they dont exist from deserialization. - if (_defaultViewportScaling.Count == 0) - { - _defaultViewportScaling.Add(new ViewportScaleOptions - { - Label = "Free Aspect", - ScaleType = ViewportScaleType.Aspect, - Size = new Int2(1, 1), - Active = true, - }); - _defaultViewportScaling.Add(new ViewportScaleOptions - { - Label = "16:9 Aspect", - ScaleType = ViewportScaleType.Aspect, - Size = new Int2(16, 9), - Active = false, - }); - _defaultViewportScaling.Add(new ViewportScaleOptions - { - Label = "16:10 Aspect", - ScaleType = ViewportScaleType.Aspect, - Size = new Int2(16, 10), - Active = false, - }); - _defaultViewportScaling.Add(new ViewportScaleOptions - { - Label = "1920x1080 Resolution (Full HD)", - ScaleType = ViewportScaleType.Resolution, - Size = new Int2(1920, 1080), - Active = false, - }); - _defaultViewportScaling.Add(new ViewportScaleOptions - { - Label = "2560x1440 Resolution (2K)", - ScaleType = ViewportScaleType.Resolution, - Size = new Int2(2560, 1440), - Active = false, - }); - } - var vsMenu = menu.AddChildMenu("Viewport Size").ContextMenu; - - CreateViewportSizingContextMenu(vsMenu); + Editor.UI.CreateViewportSizingContextMenu(vsMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, false, ChangeViewportRatio, (a, b) => + { + _defaultScaleActiveIndex = a; + _customScaleActiveIndex = b; + }); } // Take Screenshot @@ -774,243 +709,6 @@ namespace FlaxEditor.Windows } } - private void CreateViewportSizingContextMenu(ContextMenu vsMenu) - { - // Add default viewport sizing options - for (int i = 0; i < _defaultViewportScaling.Count; i++) - { - var viewportScale = _defaultViewportScaling[i]; - var button = vsMenu.AddButton(viewportScale.Label); - button.CloseMenuOnClick = false; - button.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; - button.Tag = viewportScale; - if (viewportScale.Active) - ChangeViewportRatio(viewportScale); - - button.Clicked += () => - { - if (button.Tag == null) - return; - - // Reset selected icon on all buttons - foreach (var child in vsMenu.Items) - { - if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v) - { - if (cmb == button) - { - v.Active = true; - button.Icon = Style.Current.CheckBoxTick; - ChangeViewportRatio(v); - } - else if (v.Active) - { - cmb.Icon = SpriteHandle.Invalid; - v.Active = false; - } - } - } - }; - } - if (_defaultViewportScaling.Count != 0) - vsMenu.AddSeparator(); - - // Add custom viewport options - for (int i = 0; i < _customViewportScaling.Count; i++) - { - var viewportScale = _customViewportScaling[i]; - var childCM = vsMenu.AddChildMenu(viewportScale.Label); - childCM.CloseMenuOnClick = false; - childCM.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; - childCM.Tag = viewportScale; - if (viewportScale.Active) - ChangeViewportRatio(viewportScale); - - var applyButton = childCM.ContextMenu.AddButton("Apply"); - applyButton.Tag = childCM.Tag = viewportScale; - applyButton.CloseMenuOnClick = false; - applyButton.Clicked += () => - { - if (childCM.Tag == null) - return; - - // Reset selected icon on all buttons - foreach (var child in vsMenu.Items) - { - if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v) - { - if (child == childCM) - { - v.Active = true; - childCM.Icon = Style.Current.CheckBoxTick; - ChangeViewportRatio(v); - } - else if (v.Active) - { - cmb.Icon = SpriteHandle.Invalid; - v.Active = false; - } - } - } - }; - - var deleteButton = childCM.ContextMenu.AddButton("Delete"); - deleteButton.CloseMenuOnClick = false; - deleteButton.Clicked += () => - { - if (childCM.Tag == null) - return; - - var v = (ViewportScaleOptions)childCM.Tag; - if (v.Active) - { - v.Active = false; - _defaultViewportScaling[0].Active = true; - ChangeViewportRatio(_defaultViewportScaling[0]); - } - _customViewportScaling.Remove(v); - vsMenu.DisposeAllItems(); - CreateViewportSizingContextMenu(vsMenu); - vsMenu.PerformLayout(); - }; - } - if (_customViewportScaling.Count != 0) - vsMenu.AddSeparator(); - - // Add button - var add = vsMenu.AddButton("Add..."); - add.CloseMenuOnClick = false; - add.Clicked += () => - { - var popup = new ContextMenuBase - { - Size = new Float2(230, 125), - ClipChildren = false, - CullChildren = false, - }; - popup.Show(add, new Float2(add.Width, 0)); - - var nameLabel = new Label - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Text = "Name", - HorizontalAlignment = TextAlignment.Near, - }; - nameLabel.LocalX += 10; - nameLabel.LocalY += 10; - - var nameTextBox = new TextBox - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - IsMultiline = false, - }; - nameTextBox.LocalX += 100; - nameTextBox.LocalY += 10; - - var typeLabel = new Label - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Text = "Type", - HorizontalAlignment = TextAlignment.Near, - }; - typeLabel.LocalX += 10; - typeLabel.LocalY += 35; - - var typeDropdown = new Dropdown - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Items = { "Aspect", "Resolution" }, - SelectedItem = "Aspect", - Width = nameTextBox.Width - }; - typeDropdown.LocalY += 35; - typeDropdown.LocalX += 100; - - var whLabel = new Label - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Text = "Width & Height", - HorizontalAlignment = TextAlignment.Near, - }; - whLabel.LocalX += 10; - whLabel.LocalY += 60; - - var wValue = new IntValueBox(16) - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - MinValue = 1, - Width = 55, - }; - wValue.LocalY += 60; - wValue.LocalX += 100; - - var hValue = new IntValueBox(9) - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - MinValue = 1, - Width = 55, - }; - hValue.LocalY += 60; - hValue.LocalX += 165; - - var submitButton = new Button - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Text = "Submit", - Width = 70, - }; - submitButton.LocalX += 40; - submitButton.LocalY += 90; - - submitButton.Clicked += () => - { - Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleType type); - - var combineString = type == ViewportScaleType.Aspect ? ":" : "x"; - var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem; - - var newViewportOption = new ViewportScaleOptions - { - ScaleType = type, - Label = name, - Size = new Int2(wValue.Value, hValue.Value), - }; - - _customViewportScaling.Add(newViewportOption); - vsMenu.DisposeAllItems(); - CreateViewportSizingContextMenu(vsMenu); - vsMenu.PerformLayout(); - }; - - var cancelButton = new Button - { - Parent = popup, - AnchorPreset = AnchorPresets.TopLeft, - Text = "Cancel", - Width = 70, - }; - cancelButton.LocalX += 120; - cancelButton.LocalY += 90; - - cancelButton.Clicked += () => - { - nameTextBox.Clear(); - typeDropdown.SelectedItem = "Aspect"; - hValue.Value = 9; - wValue.Value = 16; - popup.Hide(); - }; - }; - } - /// public override void Draw() { @@ -1237,8 +935,8 @@ namespace FlaxEditor.Windows writer.WriteAttributeString("ShowGUI", ShowGUI.ToString()); writer.WriteAttributeString("EditGUI", EditGUI.ToString()); writer.WriteAttributeString("ShowDebugDraw", ShowDebugDraw.ToString()); - writer.WriteAttributeString("DefaultViewportScaling", JsonSerializer.Serialize(_defaultViewportScaling)); - writer.WriteAttributeString("CustomViewportScaling", JsonSerializer.Serialize(_customViewportScaling)); + writer.WriteAttributeString("DefaultViewportScalingIndex", _defaultScaleActiveIndex.ToString()); + writer.WriteAttributeString("CustomViewportScalingIndex", _customScaleActiveIndex.ToString()); } /// @@ -1250,22 +948,30 @@ namespace FlaxEditor.Windows EditGUI = value1; if (bool.TryParse(node.GetAttribute("ShowDebugDraw"), out value1)) ShowDebugDraw = value1; - if (node.HasAttribute("CustomViewportScaling")) - _customViewportScaling = JsonSerializer.Deserialize>(node.GetAttribute("CustomViewportScaling")); + if (int.TryParse(node.GetAttribute("DefaultViewportScalingIndex"), out int value2)) + _defaultScaleActiveIndex = value2; + if (int.TryParse(node.GetAttribute("CustomViewportScalingIndex"), out value2)) + _customScaleActiveIndex = value2; - for (int i = 0; i < _customViewportScaling.Count; i++) + if (_defaultScaleActiveIndex != -1) { - if (_customViewportScaling[i].Active) - ChangeViewportRatio(_customViewportScaling[i]); + var options = Editor.UI.DefaultViewportScaleOptions; + if (options.Count > _defaultScaleActiveIndex) + ChangeViewportRatio(options[_defaultScaleActiveIndex]); + else + _defaultScaleActiveIndex = 0; } - - if (node.HasAttribute("DefaultViewportScaling")) - _defaultViewportScaling = JsonSerializer.Deserialize>(node.GetAttribute("DefaultViewportScaling")); - - for (int i = 0; i < _defaultViewportScaling.Count; i++) + + if (_customScaleActiveIndex != -1) { - if (_defaultViewportScaling[i].Active) - ChangeViewportRatio(_defaultViewportScaling[i]); + var options = Editor.UI.CustomViewportScaleOptions; + if (options.Count > _customScaleActiveIndex) + ChangeViewportRatio(options[_customScaleActiveIndex]); + else + { + _defaultScaleActiveIndex = 0; + _customScaleActiveIndex = -1; + } } } diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index d74c52623..52555f564 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -246,7 +246,7 @@ namespace FlaxEditor.Windows }); var flags = DebugCommands.GetCommandFlags(command); if (flags.HasFlag(DebugCommands.CommandFlags.Exec)) - lastItem.TintColor = new Color(0.85f, 0.85f, 1.0f, 1.0f); + lastItem.TintColor = new Color(0.75f, 0.75f, 1.0f, 1.0f); else if (flags.HasFlag(DebugCommands.CommandFlags.Read) && !flags.HasFlag(DebugCommands.CommandFlags.Write)) lastItem.TintColor = new Color(0.85f, 0.85f, 0.85f, 1.0f); lastItem.Focused += item => @@ -320,12 +320,25 @@ namespace FlaxEditor.Windows // Show commands search popup based on current text input var text = Text.Trim(); - if (text.Length != 0) + bool isWhitespaceOnly = string.IsNullOrWhiteSpace(Text) && !string.IsNullOrEmpty(Text); + if (text.Length != 0 || isWhitespaceOnly) { DebugCommands.Search(text, out var matches); - if (matches.Length != 0) + if (matches.Length != 0 || isWhitespaceOnly) { - ShowPopup(ref _searchPopup, matches, text); + string[] commands = []; + if (isWhitespaceOnly) + DebugCommands.GetAllCommands(out commands); + + ShowPopup(ref _searchPopup, isWhitespaceOnly ? commands : matches, text); + + if (isWhitespaceOnly) + { + // Scroll to and select first item for consistent behaviour + var firstItem = _searchPopup.ItemsPanel.Children[0] as Item; + _searchPopup.ScrollToAndHighlightItemByName(firstItem.Name); + } + return; } } diff --git a/Source/Engine/Animations/Graph/AnimGraph.Base.cpp b/Source/Engine/Animations/Graph/AnimGraph.Base.cpp index c49f0e26e..e4d7eda70 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Base.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Base.cpp @@ -93,6 +93,7 @@ void MultiBlendBucketInit(AnimGraphInstanceData::Bucket& bucket) void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket) { bucket.BlendPose.TransitionPosition = 0.0f; + bucket.BlendPose.BlendPoseIndex = -1; bucket.BlendPose.PreviousBlendPoseIndex = -1; } diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h index e03d84fd9..051f6613d 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.h +++ b/Source/Engine/Animations/Graph/AnimGraph.h @@ -239,7 +239,8 @@ public: struct BlendPoseBucket { float TransitionPosition; - int32 PreviousBlendPoseIndex; + int16 BlendPoseIndex; + int16 PreviousBlendPoseIndex; }; struct StateMachineBucket @@ -810,6 +811,7 @@ public: { // Copy the node transformations Platform::MemoryCopy(dstNodes->Nodes.Get(), srcNodes->Nodes.Get(), sizeof(Transform) * _skeletonNodesCount); + dstNodes->RootMotion = srcNodes->RootMotion; // Copy the animation playback state dstNodes->Position = srcNodes->Position; diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index f75a8abd1..c76bddf3f 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -676,9 +676,12 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const if (!ANIM_GRAPH_IS_VALID_PTR(poseB)) nodesB = GetEmptyNodes(); + const Transform* srcA = nodesA->Nodes.Get(); + const Transform* srcB = nodesB->Nodes.Get(); + Transform* dst = nodes->Nodes.Get(); for (int32 i = 0; i < nodes->Nodes.Count(); i++) { - Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]); + Transform::Lerp(srcA[i], srcB[i], alpha, dst[i]); } Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); nodes->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha); @@ -1263,21 +1266,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu { const auto valueA = tryGetValue(node->GetBox(1), Value::Null); const auto valueB = tryGetValue(node->GetBox(2), Value::Null); - const auto nodes = node->GetNodes(this); - - auto nodesA = static_cast(valueA.AsPointer); - auto nodesB = static_cast(valueB.AsPointer); - if (!ANIM_GRAPH_IS_VALID_PTR(valueA)) - nodesA = GetEmptyNodes(); - if (!ANIM_GRAPH_IS_VALID_PTR(valueB)) - nodesB = GetEmptyNodes(); - - for (int32 i = 0; i < nodes->Nodes.Count(); i++) - { - Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]); - } - Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); - value = nodes; + value = Blend(node, valueA, valueB, alpha, AlphaBlendMode::Linear); } break; @@ -1758,35 +1747,38 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu // [2]: int Pose Count // [3]: AlphaBlendMode Mode - // Prepare auto& bucket = context.Data->State[node->BucketIndex].BlendPose; - const int32 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]); + const int16 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]); const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]); const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses); const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt; - - // Skip if nothing to blend if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount) - { break; + + // Check if swap transition end points + if (bucket.PreviousBlendPoseIndex == poseIndex && bucket.BlendPoseIndex != poseIndex && bucket.TransitionPosition >= ANIM_GRAPH_BLEND_THRESHOLD) + { + bucket.TransitionPosition = blendDuration - bucket.TransitionPosition; + Swap(bucket.BlendPoseIndex, bucket.PreviousBlendPoseIndex); } // Check if transition is not active (first update, pose not changing or transition ended) bucket.TransitionPosition += context.DeltaTime; + bucket.BlendPoseIndex = poseIndex; if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD) { bucket.TransitionPosition = 0.0f; + bucket.BlendPoseIndex = poseIndex; bucket.PreviousBlendPoseIndex = poseIndex; - value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null); + value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null); break; } - ASSERT(bucket.PreviousBlendPoseIndex >= 0 && bucket.PreviousBlendPoseIndex < poseCount); // Blend two animations { const float alpha = bucket.TransitionPosition / blendDuration; const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null); - const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null); + const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null); value = Blend(node, valueA, valueB, alpha, mode); } diff --git a/Source/Engine/Audio/AudioListener.cpp b/Source/Engine/Audio/AudioListener.cpp index 1921bd373..9c5898b4a 100644 --- a/Source/Engine/Audio/AudioListener.cpp +++ b/Source/Engine/Audio/AudioListener.cpp @@ -23,11 +23,11 @@ void AudioListener::Update() { // Update the velocity const Vector3 pos = GetPosition(); - const float dt = Time::Update.UnscaledDeltaTime.GetTotalSeconds(); + const float dt = Math::Max(Time::Update.UnscaledDeltaTime.GetTotalSeconds(), 0.00001f); const auto prevVelocity = _velocity; _velocity = (pos - _prevPos) / dt; _prevPos = pos; - if (_velocity != prevVelocity) + if (_velocity != prevVelocity && !_velocity.IsNanOrInfinity()) { AudioBackend::Listener::VelocityChanged(_velocity); } diff --git a/Source/Engine/Audio/AudioSource.cpp b/Source/Engine/Audio/AudioSource.cpp index 98ee0f9c0..c8b0f3bab 100644 --- a/Source/Engine/Audio/AudioSource.cpp +++ b/Source/Engine/Audio/AudioSource.cpp @@ -168,8 +168,8 @@ void AudioSource::Play() } else { - // Source was nt properly added to the Audio Backend - LOG(Warning, "Cannot play unitialized audio source."); + // Source was not properly added to the Audio Backend + LOG(Warning, "Cannot play uninitialized audio source."); } } @@ -408,6 +408,9 @@ void AudioSource::Update() _startingToPlay = false; } + if (Math::NearEqual(GetTime(), _startTime) && _isActuallyPlayingSth && _startingToPlay) + ClipStarted(); + if (!UseStreaming() && Math::NearEqual(GetTime(), 0.0f) && _isActuallyPlayingSth && !_startingToPlay) { int32 queuedBuffers; @@ -423,6 +426,7 @@ void AudioSource::Update() { Stop(); } + ClipFinished(); } } @@ -493,6 +497,7 @@ void AudioSource::Update() { Stop(); } + ClipFinished(); } ASSERT(_streamingFirstChunk < clip->Buffers.Count()); diff --git a/Source/Engine/Audio/AudioSource.h b/Source/Engine/Audio/AudioSource.h index 9d6d28ab4..58903912c 100644 --- a/Source/Engine/Audio/AudioSource.h +++ b/Source/Engine/Audio/AudioSource.h @@ -76,6 +76,16 @@ public: API_FIELD(Attributes="EditorOrder(10), DefaultValue(null), EditorDisplay(\"Audio Source\")") AssetReference Clip; + /// + /// Event fired when the audio clip starts. + /// + API_EVENT() Action ClipStarted; + + /// + /// Event fired when the audio clip finishes. + /// + API_EVENT() Action ClipFinished; + /// /// Gets the velocity of the source. Determines pitch in relation to AudioListener's position. Only relevant for spatial (3D) sources. /// diff --git a/Source/Engine/Content/Assets/Animation.cpp b/Source/Engine/Content/Assets/Animation.cpp index 015f09e4e..917db28ac 100644 --- a/Source/Engine/Content/Assets/Animation.cpp +++ b/Source/Engine/Content/Assets/Animation.cpp @@ -600,7 +600,6 @@ void Animation::OnScriptingDispose() Asset::LoadResult Animation::load() { PROFILE_MEM(AnimationsData); - ScopeWriteLock systemScope(Animations::SystemLocker); // Get stream with animations data const auto dataChunk = GetChunk(0); diff --git a/Source/Engine/Content/Assets/AnimationGraph.cpp b/Source/Engine/Content/Assets/AnimationGraph.cpp index ad6353196..2823b012f 100644 --- a/Source/Engine/Content/Assets/AnimationGraph.cpp +++ b/Source/Engine/Content/Assets/AnimationGraph.cpp @@ -27,7 +27,6 @@ AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info) Asset::LoadResult AnimationGraph::load() { PROFILE_MEM(AnimationsData); - ScopeWriteLock systemScope(Animations::SystemLocker); // Get stream with graph data const auto surfaceChunk = GetChunk(0); @@ -86,7 +85,6 @@ bool AnimationGraph::InitAsAnimation(SkinnedModel* baseModel, Animation* anim, b return true; } PROFILE_MEM(AnimationsData); - ScopeWriteLock systemScope(Animations::SystemLocker); // Create Graph data MemoryWriteStream writeStream(512); @@ -172,7 +170,6 @@ bool AnimationGraph::SaveSurface(const BytesContainer& data) { if (OnCheckSave()) return true; - ScopeWriteLock systemScope(Animations::SystemLocker); ScopeLock lock(Locker); if (IsVirtual()) diff --git a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp index 812a8f090..c70a9c8a0 100644 --- a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp +++ b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp @@ -22,7 +22,6 @@ AnimationGraphFunction::AnimationGraphFunction(const SpawnParams& params, const Asset::LoadResult AnimationGraphFunction::load() { PROFILE_MEM(AnimationsData); - ScopeWriteLock systemScope(Animations::SystemLocker); // Get graph data from chunk const auto surfaceChunk = GetChunk(0); @@ -98,7 +97,6 @@ bool AnimationGraphFunction::SaveSurface(const BytesContainer& data) const { if (OnCheckSave()) return true; - ScopeWriteLock systemScope(Animations::SystemLocker); ScopeLock lock(Locker); // Set Visject Surface data diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index 1e36b36ae..019fd9dd8 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -190,16 +190,55 @@ Asset::LoadResult Material::load() // Load layer layer = MaterialLayer::Load(GetID(), &stream, _shaderHeader.Material.Info, name); - if (ContentDeprecated::Clear()) + const bool upgradeOldSpecular = _shaderHeader.Material.GraphVersion < 177; + if (ContentDeprecated::Clear() || upgradeOldSpecular) { // If encountered any deprecated data when loading graph then serialize it MaterialGraph graph; MemoryWriteStream writeStream(1024); stream.SetPosition(0); - if (!graph.Load(&stream, true) && !graph.Save(&writeStream, true)) + if (!graph.Load(&stream, true)) { - surfaceChunk->Data.Copy(ToSpan(writeStream)); - ContentDeprecated::Clear(); + if (upgradeOldSpecular) + { + // [Deprecated in 1.11] + // Specular calculations were changed to support up to 16% of reflectance via ^2 curve instead of linear up to 8% + // Insert Custom Code node that converts old materials into a new system to ensure they look the same + MaterialGraph::Node* rootNode = nullptr; + for (auto& e : graph.Nodes) + { + if (e.Type == ROOT_NODE_TYPE) + { + rootNode = &e; + break; + } + } + const auto& specularBoxInfo = MaterialGenerator::GetMaterialRootNodeBox(MaterialGraphBoxes::Specular); + auto specularBox = rootNode ? rootNode->GetBox(specularBoxInfo.ID) : nullptr; + if (specularBox && specularBox->HasConnection()) + { + auto& customCodeNode = graph.Nodes.AddOne(); + customCodeNode.ID = graph.Nodes.Count() + 1000; + customCodeNode.Type = GRAPH_NODE_MAKE_TYPE(1, 8); + customCodeNode.Boxes.Resize(2); + customCodeNode.Boxes[0] = MaterialGraphBox(&customCodeNode, 0, VariantType::Float4); // Input0 + customCodeNode.Boxes[1] = MaterialGraphBox(&customCodeNode, 8, VariantType::Float4); // Output0 + customCodeNode.Values.Resize(1); + customCodeNode.Values[0] = TEXT("// Convert old Specular value to a new range\nOutput0.x = min(Input0.x * 0.5f, 0.6f);"); + auto specularSourceBox = specularBox->Connections[0]; + specularBox->Connections.Clear(); + specularSourceBox->Connections.Clear(); +#define CONNECT(boxA, boxB) boxA->Connections.Add(boxB); boxB->Connections.Add(boxA) + CONNECT(specularSourceBox, (&customCodeNode.Boxes[0])); // Specular -> Input0 + CONNECT((&customCodeNode.Boxes[1]), specularBox); // Output0 -> Specular +#undef CONNECT + } + } + if (!graph.Save(&writeStream, true)) + { + surfaceChunk->Data.Copy(ToSpan(writeStream)); + ContentDeprecated::Clear(); + } } } } diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp index 7d6c9d7fc..b3710ebbd 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.cpp +++ b/Source/Engine/Content/Assets/MaterialInstance.cpp @@ -90,9 +90,11 @@ void MaterialInstance::OnBaseParamsChanged() // Get the newest parameters baseParams->Clone(Params); +#if 0 // Override all public parameters by default for (auto& param : Params) param.SetIsOverride(param.IsPublic()); +#endif // Copy previous parameters values for (int32 i = 0; i < oldParams.Count(); i++) diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp index 1830f40de..829eaeb11 100644 --- a/Source/Engine/Content/Assets/Model.cpp +++ b/Source/Engine/Content/Assets/Model.cpp @@ -33,12 +33,14 @@ class StreamModelSDFTask : public GPUUploadTextureMipTask { private: WeakAssetReference _asset; + FlaxStorageReference _dataRef; FlaxStorage::LockData _dataLock; public: StreamModelSDFTask(Model* model, GPUTexture* texture, const Span& data, int32 mipIndex, int32 rowPitch, int32 slicePitch) : GPUUploadTextureMipTask(texture, mipIndex, data, rowPitch, slicePitch, false) , _asset(model) + , _dataRef(model->Storage) , _dataLock(model->Storage->Lock()) { } @@ -59,6 +61,7 @@ public: void OnEnd() override { _dataLock.Release(); + _dataRef = FlaxStorageReference(); // Base GPUUploadTextureMipTask::OnEnd(); diff --git a/Source/Engine/Content/Assets/ModelBase.cpp b/Source/Engine/Content/Assets/ModelBase.cpp index 0946e6160..599caa810 100644 --- a/Source/Engine/Content/Assets/ModelBase.cpp +++ b/Source/Engine/Content/Assets/ModelBase.cpp @@ -3,6 +3,7 @@ #include "ModelBase.h" #include "Engine/Core/Log.h" #include "Engine/Core/Math/Transform.h" +#include "Engine/Core/Config/BuildSettings.h" #include "Engine/Content/WeakAssetReference.h" #include "Engine/Serialization/MemoryReadStream.h" #include "Engine/Profiler/ProfilerMemory.h" @@ -666,11 +667,42 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l return true; } + // Process mesh data if need to decide vertex buffer on format dynamically + auto positionFormat = modelData.PositionFormat; + if (positionFormat == ModelData::PositionFormats::Automatic) + { + const float maxPositionError = BuildSettings::Get()->MaxMeshPositionError; // In world-units + const float maxPositionErrorSq = maxPositionError * maxPositionError; + if (maxPositionErrorSq > 0.0f) + { + positionFormat = ModelData::PositionFormats::Float16; + const Float3* positions = mesh.Positions.Get(); + for (int32 i = 0; i < mesh.Positions.Count(); i++) + { + // Encode to Half3 and decode back to see the position error + Float3 position = positions[i]; + Half3 encoded(position); + Float3 decoded = encoded.ToFloat3(); + if (Float3::DistanceSquared(position, decoded) > maxPositionErrorSq) + { + // Cannot use lower quality so go back to full precision + positionFormat = ModelData::PositionFormats::Float32; + break; + } + } + } + else + { + // Full precision as default + positionFormat = ModelData::PositionFormats::Float32; + } + } + // Define vertex buffers layout and packing Array> vbElements; const bool useSeparatePositions = !isSkinned; const bool useSeparateColors = !isSkinned; - PixelFormat positionsFormat = modelData.PositionFormat == ModelData::PositionFormats::Float32 ? PixelFormat::R32G32B32_Float : PixelFormat::R16G16B16A16_Float; + PixelFormat positionsFormat = positionFormat == ModelData::PositionFormats::Float32 ? PixelFormat::R32G32B32_Float : PixelFormat::R16G16B16A16_Float; PixelFormat texCoordsFormat = modelData.TexCoordFormat == ModelData::TexCoordFormats::Float16 ? PixelFormat::R16G16_Float : PixelFormat::R8G8_UNorm; PixelFormat blendIndicesFormat = PixelFormat::R8G8B8A8_UInt; PixelFormat blendWeightsFormat = PixelFormat::R8G8B8A8_UNorm; @@ -684,7 +716,6 @@ bool ModelBase::SaveLOD(WriteStream& stream, const ModelData& modelData, int32 l } { byte vbIndex = 0; - // TODO: add option to quantize vertex attributes (eg. 8-bit blend weights, 8-bit texcoords) // Position if (useSeparatePositions) diff --git a/Source/Engine/Content/Assets/Texture.cpp b/Source/Engine/Content/Assets/Texture.cpp index e31b40a25..4e3aec94d 100644 --- a/Source/Engine/Content/Assets/Texture.cpp +++ b/Source/Engine/Content/Assets/Texture.cpp @@ -36,7 +36,7 @@ bool Texture::Save(const StringView& path) bool Texture::Save(const StringView& path, const InitData* customData) { - if (OnCheckSave()) + if (OnCheckSave(path)) return true; ScopeLock lock(Locker); diff --git a/Source/Engine/Content/Storage/FlaxStorageReference.h b/Source/Engine/Content/Storage/FlaxStorageReference.h index 94929baa4..402e312d8 100644 --- a/Source/Engine/Content/Storage/FlaxStorageReference.h +++ b/Source/Engine/Content/Storage/FlaxStorageReference.h @@ -13,6 +13,11 @@ private: FlaxStorage* _storage; public: + FlaxStorageReference() + : _storage(nullptr) + { + } + FlaxStorageReference(FlaxStorage* storage) : _storage(storage) { diff --git a/Source/Engine/ContentImporters/CreateMaterial.cpp b/Source/Engine/ContentImporters/CreateMaterial.cpp index 3991585a3..a41d09454 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.cpp +++ b/Source/Engine/ContentImporters/CreateMaterial.cpp @@ -93,14 +93,15 @@ namespace }; template - void AddInput(MaterialLayer* layer, Meta11 meta, MaterialGraphBoxes box, const Guid& texture, const T& value, const T& defaultValue, const Float2& pos, ShaderGraphNode<>** outTextureNode = nullptr) + void AddInput(MaterialLayer* layer, Meta11 meta, MaterialGraphBoxes box, const Guid& texture, const T& value, const T& defaultValue, const Float2& pos, ShaderGraphNode<>** outTextureNode = nullptr, uint8 channel = MAX_uint8) { auto textureNode = AddTextureNode(layer, texture); auto valueNode = AddValueNode(layer, value, defaultValue); + auto textureNodeBox = channel == MAX_uint8 ? 1 : channel + 2; // Color or specific channel (RGBA) if (textureNode && valueNode) { auto diffuseMultiply = AddMultiplyNode(layer); - CONNECT(diffuseMultiply->Boxes[0], textureNode->Boxes[1]); + CONNECT(diffuseMultiply->Boxes[0], textureNode->Boxes[textureNodeBox]); CONNECT(diffuseMultiply->Boxes[1], valueNode->Boxes[0]); CONNECT(layer->Root->Boxes[static_cast(box)], diffuseMultiply->Boxes[2]); SET_POS(valueNode, pos + Float2(-467.7404, 91.41332)); @@ -109,7 +110,7 @@ namespace } else if (textureNode) { - CONNECT(layer->Root->Boxes[static_cast(box)], textureNode->Boxes[1]); + CONNECT(layer->Root->Boxes[static_cast(box)], textureNode->Boxes[textureNodeBox]); SET_POS(textureNode, pos + Float2(-293.5272f, -2.926111f)); } else if (valueNode) @@ -178,8 +179,9 @@ CreateAssetResult CreateMaterial::Create(CreateAssetContext& context) // Opacity AddInput(layer, meta, MaterialGraphBoxes::Opacity, options.Opacity.Texture, options.Opacity.Value, 1.0f, Float2(0, 400)); - // Opacity - AddInput(layer, meta, MaterialGraphBoxes::Roughness, options.Roughness.Texture, options.Roughness.Value, 0.5f, Float2(200, 400)); + // Roughness + Metalness + AddInput(layer, meta, MaterialGraphBoxes::Roughness, options.Roughness.Texture, options.Roughness.Value, 0.5f, Float2(200, 400), nullptr, options.Roughness.Channel); + AddInput(layer, meta, MaterialGraphBoxes::Metalness, options.Metalness.Texture, options.Metalness.Value, 0.0f, Float2(200, 600), nullptr, options.Metalness.Channel); // Normal auto normalMap = AddTextureNode(layer, options.Normals.Texture, true); diff --git a/Source/Engine/ContentImporters/CreateMaterial.h b/Source/Engine/ContentImporters/CreateMaterial.h index 6b37067e8..df0680e18 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.h +++ b/Source/Engine/ContentImporters/CreateMaterial.h @@ -40,9 +40,17 @@ public: struct { float Value = 0.5f; + uint8 Channel = 0; Guid Texture = Guid::Empty; } Roughness; + struct + { + float Value = 0.0f; + uint8 Channel = 0; + Guid Texture = Guid::Empty; + } Metalness; + struct { Guid Texture = Guid::Empty; diff --git a/Source/Engine/ContentImporters/ImportModel.cpp b/Source/Engine/ContentImporters/ImportModel.cpp index be71236ab..91547dc8d 100644 --- a/Source/Engine/ContentImporters/ImportModel.cpp +++ b/Source/Engine/ContentImporters/ImportModel.cpp @@ -26,6 +26,7 @@ #include "Engine/Utilities/RectPack.h" #include "Engine/Scripting/Scripting.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Editor/Utilities/EditorUtilities.h" #include "AssetsImportingManager.h" bool ImportModel::TryGetImportOptions(const StringView& path, Options& options) @@ -281,13 +282,19 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context) // Import all of the objects recursive but use current model data to skip loading file again options.Cached = &cached; - Function splitImport = [&context, &autoImportOutput](Options& splitOptions, const StringView& objectName, String& outputPath, MeshData* meshData) + HashSet objectNames; + Function splitImport = [&context, &autoImportOutput, &objectNames](Options& splitOptions, const StringView& objectName, String& outputPath, MeshData* meshData) { // Recursive importing of the split object String postFix = objectName; const int32 splitPos = postFix.FindLast(TEXT('|')); - if (splitPos != -1) + if (splitPos != -1 && splitPos + 1 < postFix.Length()) postFix = postFix.Substring(splitPos + 1); + EditorUtilities::ValidatePathChars(postFix); // Ensure name is valid path + int32 duplicate = 0; + String postFixPre = postFix; + while (!objectNames.Add(postFix)) // Ensure name is unique + postFix = String::Format(TEXT("{} {}"), postFixPre, duplicate++); // TODO: check for name collisions with material/texture assets outputPath = autoImportOutput / String(StringUtils::GetFileNameWithoutExtension(context.TargetAssetPath)) + TEXT(" ") + postFix + TEXT(".flax"); splitOptions.SubAssetFolder = TEXT(" "); // Use the same folder as asset as they all are imported to the subdir for the prefab (see SubAssetFolder usage above) diff --git a/Source/Engine/Core/Config/BuildSettings.h b/Source/Engine/Core/Config/BuildSettings.h index 4251798c1..54700278e 100644 --- a/Source/Engine/Core/Config/BuildSettings.h +++ b/Source/Engine/Core/Config/BuildSettings.h @@ -89,6 +89,12 @@ public: API_FIELD(Attributes="EditorOrder(2100), EditorDisplay(\"Content\")") bool SkipDefaultFonts = false; + /// + /// The maximum acceptable mesh vertex position error (in world units) for data quantization. Use 0 to disable this feature. Affects meshes during import (or reimpport). + /// + API_FIELD(Attributes="EditorOrder(2200), EditorDisplay(\"Content\"), ValueCategory(Utils.ValueCategory.Distance)") + float MaxMeshPositionError = 0.5f; + /// /// If checked, .NET Runtime won't be packaged with a game and will be required by user to be installed on system upon running game build. Available only on supported platforms such as Windows, Linux and macOS. /// diff --git a/Source/Engine/Core/Math/BoundingFrustum.cpp b/Source/Engine/Core/Math/BoundingFrustum.cpp index e296fa1a8..e0697ce5e 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.cpp +++ b/Source/Engine/Core/Math/BoundingFrustum.cpp @@ -63,9 +63,16 @@ void BoundingFrustum::SetMatrix(const Matrix& matrix) Plane BoundingFrustum::GetPlane(int32 index) const { - if (index > 5) - return Plane(); - return _planes[index]; + switch (index) + { + case 0: return _pLeft; + case 1: return _pRight; + case 2: return _pTop; + case 3: return _pBottom; + case 4: return _pNear; + case 5: return _pFar; + default: return Plane(); + } } static Vector3 Get3PlanesInterPoint(const Plane& p1, const Plane& p2, const Plane& p3) diff --git a/Source/Engine/Core/Math/BoundingFrustum.cs b/Source/Engine/Core/Math/BoundingFrustum.cs index 6f6e034ce..4f1e27e1e 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.cs +++ b/Source/Engine/Core/Math/BoundingFrustum.cs @@ -182,7 +182,7 @@ namespace FlaxEngine /// /// Returns one of the 6 planes related to this frustum. /// - /// Plane index where 0 fro Left, 1 for Right, 2 for Top, 3 for Bottom, 4 for Near, 5 for Far + /// Plane index where 0 for Left, 1 for Right, 2 for Top, 3 for Bottom, 4 for Near, 5 for Far /// The frustum plane. public Plane GetPlane(int index) { diff --git a/Source/Engine/Core/Math/BoundingFrustum.h b/Source/Engine/Core/Math/BoundingFrustum.h index 30eb70f43..a3a5442e9 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.h +++ b/Source/Engine/Core/Math/BoundingFrustum.h @@ -148,13 +148,13 @@ public: Plane GetPlane(int32 index) const; /// - /// Gets the the 8 corners of the frustum: Near1 (near right down corner), Near2 (near right top corner), Near3 (near Left top corner), Near4 (near Left down corner), Far1 (far right down corner), Far2 (far right top corner), Far3 (far left top corner), Far4 (far left down corner). + /// Gets the 8 corners of the frustum: Near1 (near right down corner), Near2 (near right top corner), Near3 (near Left top corner), Near4 (near Left down corner), Far1 (far right down corner), Far2 (far right top corner), Far3 (far left top corner), Far4 (far left down corner). /// /// The corners. void GetCorners(Float3 corners[8]) const; /// - /// Gets the the 8 corners of the frustum: Near1 (near right down corner), Near2 (near right top corner), Near3 (near Left top corner), Near4 (near Left down corner), Far1 (far right down corner), Far2 (far right top corner), Far3 (far left top corner), Far4 (far left down corner). + /// Gets the 8 corners of the frustum: Near1 (near right down corner), Near2 (near right top corner), Near3 (near Left top corner), Near4 (near Left down corner), Far1 (far right down corner), Far2 (far right top corner), Far3 (far left top corner), Far4 (far left down corner). /// /// The corners. void GetCorners(Double3 corners[8]) const; diff --git a/Source/Engine/Debug/DebugCommands.cpp b/Source/Engine/Debug/DebugCommands.cpp index d36c8b489..fa171d5dd 100644 --- a/Source/Engine/Debug/DebugCommands.cpp +++ b/Source/Engine/Debug/DebugCommands.cpp @@ -460,6 +460,14 @@ void DebugCommands::InitAsync() AsyncTask = Task::StartNew(InitCommands); } +void DebugCommands::GetAllCommands(Array& commands) +{ + EnsureInited(); + ScopeLock lock(Locker); + for (const auto& command : Commands) + commands.Add(command.Name); +} + DebugCommands::CommandFlags DebugCommands::GetCommandFlags(StringView command) { CommandFlags result = CommandFlags::None; diff --git a/Source/Engine/Debug/DebugCommands.h b/Source/Engine/Debug/DebugCommands.h index 73b2def69..f25fe0581 100644 --- a/Source/Engine/Debug/DebugCommands.h +++ b/Source/Engine/Debug/DebugCommands.h @@ -46,6 +46,12 @@ public: /// API_FUNCTION() static void InitAsync(); + /// + /// Gets all available commands. + /// + /// The output list of all commands (unsorted). + API_FUNCTION() static void GetAllCommands(API_PARAM(Out) Array& commands); + /// /// Returns flags of the command. /// diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 2f063e2c6..7c798f88f 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -853,7 +853,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe auto vb = DebugDrawVB->GetBuffer(); // Draw with depth test - if (depthTestLines.VertexCount + depthTestTriangles.VertexCount + depthTestWireTriangles.VertexCount > 0) + if (depthTestLines.VertexCount + depthTestTriangles.VertexCount + depthTestWireTriangles.VertexCount + Context->DebugDrawDepthTest.GeometryBuffers.Count() > 0) { if (data.EnableDepthTest) context->BindSR(0, renderContext.Buffers->DepthBuffer); @@ -909,7 +909,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe } // Draw without depth - if (defaultLines.VertexCount + defaultTriangles.VertexCount + defaultWireTriangles.VertexCount > 0) + if (defaultLines.VertexCount + defaultTriangles.VertexCount + defaultWireTriangles.VertexCount + Context->DebugDrawDefault.GeometryBuffers.Count() > 0) { context->SetRenderTarget(target); diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 7c1e2e64a..7af32fc9b 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -835,7 +835,7 @@ namespace FlaxEngine.Interop { object fieldOwner = fieldOwnerHandle.Target; IntPtr fieldRef; -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHolder field = Unsafe.As(fieldHandle.Target); fieldRef = IntPtr.Zero; Debug.LogError("Not supported FieldGetValueReference"); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 7d16b4752..2d8f8db84 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -107,17 +107,13 @@ namespace FlaxEngine.Interop { } -#if !USE_AOT +#if !USE_AOT && !DOTNET_HOST_MONO [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__unmanagedPtr")] extern static ref IntPtr GetUnmanagedPtrFieldReference(Object obj); [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "__internalId")] extern static ref Guid GetInternalIdFieldReference(Object obj); - // Cache offsets to frequently accessed fields of FlaxEngine.Object - private static int unmanagedPtrFieldOffset = IntPtr.Size + (Unsafe.Read((typeof(FlaxEngine.Object).GetField("__unmanagedPtr", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF); - private static int internalIdFieldOffset = IntPtr.Size + (Unsafe.Read((typeof(FlaxEngine.Object).GetField("__internalId", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF); - [UnmanagedCallersOnly] internal static void ScriptingObjectSetInternalValues(ManagedHandle objectHandle, IntPtr unmanagedPtr, IntPtr idPtr) { @@ -418,14 +414,21 @@ namespace FlaxEngine.Interop if (field.IsLiteral) return 0; +#if DOTNET_HOST_CORECLR // Get the address of the field, source: https://stackoverflow.com/a/56512720 int fieldOffset = Unsafe.Read((field.FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF; if (!type.IsValueType) fieldOffset += IntPtr.Size; return fieldOffset; +#elif DOTNET_HOST_MONO + // Get the address from _MonoClassField::offset, source: https://meetemq.com/2023/09/10/nets-fields-and-their-offsets/ + var fieldOffsetPtr = (IntPtr*)field.FieldHandle.Value; // Pointer to MonoClassField + fieldOffsetPtr += 3; // Skip three pointers (type, name, parent_and_flags) + return *(int*)fieldOffsetPtr - IntPtr.Size * 2; // Load the value of a pointer (4 bytes, int32), then subtracting 16 bytes from it (2 pointers for vtable and threadsync) +#endif } -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO /// /// Helper utility to set field of the referenced value via reflection. /// @@ -756,12 +759,12 @@ namespace FlaxEngine.Interop } } } - throw new NativeInteropException($"Invalid field with offset {fieldOffset} to marshal for type {typeof(T).Name}"); + throw new NativeInteropException($"Invalid field with offset {fieldOffset} to marshal for type {typeof(T).FullName}"); } private static void ToManagedFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct { -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO IntPtr fieldValue = Unsafe.Read(nativeFieldPtr.ToPointer()); FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #else @@ -773,7 +776,7 @@ namespace FlaxEngine.Interop private static void ToManagedFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class { -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO IntPtr fieldValue = Unsafe.Read(nativeFieldPtr.ToPointer()); FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #else @@ -785,7 +788,7 @@ namespace FlaxEngine.Interop private static void ToNativeFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct { -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO object boxed = field.GetValue(fieldOwner); IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed)); #else @@ -797,7 +800,7 @@ namespace FlaxEngine.Interop private static void ToNativeFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class { -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO object boxed = field.GetValue(fieldOwner); IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed)); #else @@ -845,13 +848,13 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); } -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = default; #else ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, nativeFieldPtr, false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -866,13 +869,13 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); } -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = default; #else ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, nativeFieldPtr, false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -885,13 +888,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField[] fieldValue = (TField[])field.GetValue(fieldOwner); #else ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -904,13 +907,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField[] fieldValue = null; #else ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -925,7 +928,7 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - startPtr).ToInt32(); } -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = (TField)field.GetValue(fieldOwner); #else ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); @@ -943,7 +946,7 @@ namespace FlaxEngine.Interop fieldSize += (nativeFieldPtr - startPtr).ToInt32(); } -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = (TField)field.GetValue(fieldOwner); #else ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); @@ -978,13 +981,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = null; #else ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -996,13 +999,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = default; #else ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -1014,13 +1017,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField[] fieldValue = null; #else ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -1032,13 +1035,13 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField[] fieldValue = null; #else ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); #endif MarshalHelper.ToManaged(ref fieldValue, Unsafe.Read(nativeFieldPtr.ToPointer()), false); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue); #endif } @@ -1050,7 +1053,7 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = (TField)field.GetValue(fieldOwner); #else ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner); @@ -1065,7 +1068,7 @@ namespace FlaxEngine.Interop nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size); fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32(); -#if USE_AOT +#if USE_AOT || DOTNET_HOST_MONO TField fieldValue = (TField)field.GetValue(fieldOwner); #else ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner); @@ -1439,7 +1442,7 @@ namespace FlaxEngine.Interop return RuntimeHelpers.GetUninitializedObject(wrappedType); } -#if !USE_AOT +#if !USE_AOT && !DOTNET_HOST_MONO internal object CreateScriptingObject(IntPtr unmanagedPtr, IntPtr idPtr) { object obj = RuntimeHelpers.GetUninitializedObject(wrappedType); diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 8a0e75a6e..ddc3468f7 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -323,6 +323,7 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, draw.Bounds = sphere; draw.PerInstanceRandom = instance.Random; draw.DrawModes = type._drawModes; + draw.SetStencilValue(_layer); type.Model->Draw(renderContext, draw); //DebugDraw::DrawSphere(instance.Bounds, Color::YellowGreen); @@ -1182,6 +1183,7 @@ void Foliage::Draw(RenderContext& renderContext) draw.Bounds = instance.Bounds; draw.PerInstanceRandom = instance.Random; draw.DrawModes = type.DrawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode); + draw.SetStencilValue(_layer); type.Model->Draw(renderContext, draw); return; } diff --git a/Source/Engine/Graphics/Config.h b/Source/Engine/Graphics/Config.h index 542669f03..43fb319bf 100644 --- a/Source/Engine/Graphics/Config.h +++ b/Source/Engine/Graphics/Config.h @@ -70,7 +70,7 @@ // Default depth buffer pixel format #ifndef GPU_DEPTH_BUFFER_PIXEL_FORMAT -#define GPU_DEPTH_BUFFER_PIXEL_FORMAT PixelFormat::D32_Float +#define GPU_DEPTH_BUFFER_PIXEL_FORMAT PixelFormat::D24_UNorm_S8_UInt #endif // Enable/disable gpu resources naming diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index eda66d95e..be41ad228 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -392,6 +392,8 @@ bool GPUDevice::Init() LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory)); if (!Limits.HasCompute) LOG(Warning, "Compute Shaders are not supported"); + for (const auto& videoOutput : VideoOutputs) + LOG(Info, "Video output '{0}' {1}x{2} {3} Hz", videoOutput.Name, videoOutput.Width, videoOutput.Height, videoOutput.RefreshRate); Engine::RequestingExit.Bind(this); return false; } @@ -725,6 +727,7 @@ void GPUDevice::Draw() void GPUDevice::Dispose() { RenderList::CleanupCache(); + VideoOutputs.Resize(0); VideoOutputModes.Resize(0); } diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index 8914085eb..8f9393a5b 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -54,7 +54,40 @@ public: }; /// - /// Describes a video output display mode. + /// Describes a video output display (monitor). + /// + API_STRUCT() struct VideoOutput + { + DECLARE_SCRIPTING_TYPE_NO_SPAWN(VideoOutputMode); + + /// + /// The display name. + /// + API_FIELD() String Name; + + /// + /// The native screen resolution width (in pixel). + /// + API_FIELD() uint32 Width = 0; + + /// + /// The native screen resolution height (in pixel). + /// + API_FIELD() uint32 Height = 0; + + /// + /// The maximum screen refresh rate (in hertz). + /// + API_FIELD() float RefreshRate = 0; + + /// + /// Flag that indicates that monitor supports displaying High Dynamic Range colors. + /// + API_FIELD() bool HDR = false; + }; + + /// + /// Describes a video output display mode (monitor screen mode). /// API_STRUCT() struct VideoOutputMode { @@ -73,7 +106,12 @@ public: /// /// The screen refresh rate (in hertz). /// - API_FIELD() uint32 RefreshRate; + API_FIELD() float RefreshRate; + + /// + /// The index of the VideoOutput from the device monitors list. + /// + API_FIELD() int32 VideoOutputIndex; }; /// @@ -134,6 +172,11 @@ public: /// API_FIELD(ReadOnly) GPULimits Limits; + /// + /// The available video outputs (monitors). + /// + API_FIELD(ReadOnly) Array VideoOutputs; + /// /// The available video output modes. /// diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp index ffc8fa241..7cf9c96d1 100644 --- a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp @@ -17,6 +17,8 @@ PACK_STRUCT(struct DecalMaterialShaderData { Matrix WorldMatrix; Matrix InvWorld; Matrix SvPositionToWorld; + Float3 Padding0; + uint32 RenderLayersMask; }); DrawPass DecalMaterialShader::GetDrawModes() const @@ -50,6 +52,7 @@ void DecalMaterialShader::Bind(BindParameters& params) GPUTexture* depthBuffer = params.RenderContext.Buffers->DepthBuffer; GPUTextureView* depthBufferView = EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView) ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View(); context->BindSR(0, depthBufferView); + context->BindSR(1, depthBuffer->ViewStencil()); // Setup material constants { @@ -68,6 +71,7 @@ void DecalMaterialShader::Bind(BindParameters& params) -1.0f, 1.0f, 0, 1); const Matrix svPositionToWorld = offsetMatrix * view.IVP; Matrix::Transpose(svPositionToWorld, materialData->SvPositionToWorld); + materialData->RenderLayersMask = (uint32)drawCall.SortKey; // Provided by GBufferPass::DrawDecals } // Bind constants diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 5f0abad33..bbcdc8207 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -85,13 +85,10 @@ void DeferredMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminant) { // Invert culling when scale is negative - if (cullMode == CullMode::Normal) - cullMode = CullMode::Inverted; - else - cullMode = CullMode::Normal; + cullMode = cullMode == CullMode::Normal ? CullMode::Inverted : CullMode::Normal; } ASSERT_LOW_LAYER(!(useSkinning && params.Instanced)); // No support for instancing skinned meshes const auto cache = params.Instanced ? &_cacheInstanced : &_cache; @@ -101,6 +98,7 @@ void DeferredMaterialShader::Bind(BindParameters& params) // Bind pipeline context->SetState(state); + context->SetStencilRef(drawCall.StencilValue); } void DeferredMaterialShader::Unload() @@ -137,6 +135,10 @@ bool DeferredMaterialShader::Load() } #endif + psDesc.StencilEnable = true; + psDesc.StencilReadMask = 0; + psDesc.StencilPassOp = StencilOperation::Replace; + // GBuffer Pass psDesc.VS = _shader->GetVS("VS"); failed |= psDesc.VS == nullptr; @@ -160,6 +162,9 @@ bool DeferredMaterialShader::Load() psDesc.PS = _shader->GetPS("PS_GBuffer"); _cache.DefaultSkinned.Init(psDesc); + psDesc.StencilEnable = false; + psDesc.StencilPassOp = StencilOperation::Keep; + #if USE_EDITOR if (_shader->HasShader("PS_QuadOverdraw")) { diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index 3efd9a2bc..6260163f4 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -62,7 +62,7 @@ void DeformableMaterialShader::Bind(BindParameters& params) { Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(drawCall.Deformable.LocalMatrix, materialData->LocalMatrix); - materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; + materialData->WorldDeterminantSign = drawCall.WorldDeterminant ? -1.0f : 1.0f; materialData->Segment = drawCall.Deformable.Segment; materialData->ChunksPerSegment = drawCall.Deformable.ChunksPerSegment; materialData->MeshMinZ = drawCall.Deformable.MeshMinZ; @@ -84,13 +84,10 @@ void DeformableMaterialShader::Bind(BindParameters& params) // Select pipeline state based on current pass and render mode const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != MaterialFeaturesFlags::None || view.Mode == ViewMode::Wireframe; CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode; - if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminant) { // Invert culling when scale is negative - if (cullMode == CullMode::Normal) - cullMode = CullMode::Inverted; - else - cullMode = CullMode::Normal; + cullMode = cullMode == CullMode::Normal ? CullMode::Inverted : CullMode::Normal; } PipelineStateCache* psCache = _cache.GetPS(view.Pass); ASSERT(psCache); @@ -98,6 +95,7 @@ void DeformableMaterialShader::Bind(BindParameters& params) // Bind pipeline context->SetState(state); + context->SetStencilRef(drawCall.StencilValue); } void DeformableMaterialShader::Unload() @@ -139,10 +137,17 @@ bool DeformableMaterialShader::Load() { _drawModes |= DrawPass::GBuffer | DrawPass::GlobalSurfaceAtlas; + psDesc.StencilEnable = true; + psDesc.StencilReadMask = 0; + psDesc.StencilPassOp = StencilOperation::Replace; + // GBuffer Pass psDesc.VS = _shader->GetVS("VS_SplineModel"); psDesc.PS = _shader->GetPS("PS_GBuffer"); _cache.Default.Init(psDesc); + + psDesc.StencilEnable = false; + psDesc.StencilPassOp = StencilOperation::Keep; } else { diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index a966507d8..72ec3c7bd 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -80,13 +80,10 @@ void ForwardMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminant) { // Invert culling when scale is negative - if (cullMode == CullMode::Normal) - cullMode = CullMode::Inverted; - else - cullMode = CullMode::Normal; + cullMode = cullMode == CullMode::Normal ? CullMode::Inverted : CullMode::Normal; } ASSERT_LOW_LAYER(!(useSkinning && params.Instanced)); // No support for instancing skinned meshes const auto cacheObj = params.Instanced ? &_cacheInstanced : &_cache; diff --git a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp index 874694702..834fc35fd 100644 --- a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp @@ -24,7 +24,7 @@ PACK_STRUCT(struct GUIMaterialShaderData { Float4 ScreenSize; Float4 ViewSize; Float3 ViewPadding0; - float UnscaledTimeParam; + float ScaledTimeParam; }); void GUIMaterialShader::Bind(BindParameters& params) @@ -58,7 +58,7 @@ void GUIMaterialShader::Bind(BindParameters& params) materialData->ViewFar = 0.0f; materialData->ViewDir = Float3::Forward; materialData->TimeParam = params.Time; - materialData->UnscaledTimeParam = params.UnscaledTime; + materialData->ScaledTimeParam = params.ScaledTime; materialData->ViewInfo = Float4::Zero; auto& viewport = Render2D::GetViewport(); materialData->ScreenSize = Float4(viewport.Width, viewport.Height, 1.0f / viewport.Width, 1.0f / viewport.Height); diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h index 23d06589b..40d197ddb 100644 --- a/Source/Engine/Graphics/Materials/IMaterial.h +++ b/Source/Engine/Graphics/Materials/IMaterial.h @@ -148,7 +148,7 @@ public: const ::DrawCall* DrawCall = nullptr; MaterialParamsLink* ParamsLink = nullptr; void* CustomData = nullptr; - float Time, UnscaledTime; + float Time, ScaledTime; bool Instanced = false; /// @@ -156,8 +156,8 @@ public: /// GPUTextureView* Input = nullptr; - BindParameters(::GPUContext* context, const ::RenderContext& renderContext); - BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const ::DrawCall& drawCall, bool instanced = false); + FLAXENGINE_API BindParameters(::GPUContext* context, const ::RenderContext& renderContext); + FLAXENGINE_API BindParameters(::GPUContext* context, const ::RenderContext& renderContext, const ::DrawCall& drawCall, bool instanced = false); // Per-view shared constant buffer (see ViewData in MaterialCommon.hlsl). static GPUConstantBuffer* PerViewConstants; diff --git a/Source/Engine/Graphics/Materials/MaterialInfo.h b/Source/Engine/Graphics/Materials/MaterialInfo.h index 69a9bd0a6..84771fed8 100644 --- a/Source/Engine/Graphics/Materials/MaterialInfo.h +++ b/Source/Engine/Graphics/Materials/MaterialInfo.h @@ -444,6 +444,16 @@ API_ENUM() enum class MaterialSceneTextures /// The scene world-space position (relative to the render view origin). /// WorldPosition = 11, + + /// + /// The scene stencil. + /// + SceneStencil = 12, + + /// + /// The object layer index. + /// + ObjectLayer = 13, }; /// diff --git a/Source/Engine/Graphics/Materials/MaterialParams.cpp b/Source/Engine/Graphics/Materials/MaterialParams.cpp index 2fa5a8e5f..05bb29c4a 100644 --- a/Source/Engine/Graphics/Materials/MaterialParams.cpp +++ b/Source/Engine/Graphics/Materials/MaterialParams.cpp @@ -393,6 +393,10 @@ void MaterialParameter::Bind(BindMeta& meta) const case MaterialSceneTextures::Specular: view = meta.CanSampleGBuffer ? meta.Buffers->GBuffer2->View() : nullptr; break; + case MaterialSceneTextures::SceneStencil: + case MaterialSceneTextures::ObjectLayer: + view = meta.CanSampleDepth ? meta.Buffers->DepthBuffer->ViewStencil() : nullptr; + break; default: ; } } diff --git a/Source/Engine/Graphics/Materials/MaterialShader.cpp b/Source/Engine/Graphics/Materials/MaterialShader.cpp index f1e9fd542..5d929320d 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShader.cpp @@ -38,14 +38,14 @@ GPU_CB_STRUCT(MaterialShaderDataPerView { Float3 LargeWorldsChunkIndex; float LargeWorldsChunkSize; Float3 ViewPadding0; - float UnscaledTimeParam; + float ScaledTimeParam; }); IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext) : GPUContext(context) , RenderContext(renderContext) - , Time(Time::Draw.Time.GetTotalSeconds()) - , UnscaledTime(Time::Draw.UnscaledTime.GetTotalSeconds()) + , Time(Time::Draw.UnscaledTime.GetTotalSeconds()) + , ScaledTime(Time::Draw.Time.GetTotalSeconds()) { } @@ -53,8 +53,8 @@ IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderC : GPUContext(context) , RenderContext(renderContext) , DrawCall(&drawCall) - , Time(Time::Draw.Time.GetTotalSeconds()) - , UnscaledTime(Time::Draw.UnscaledTime.GetTotalSeconds()) + , Time(Time::Draw.UnscaledTime.GetTotalSeconds()) + , ScaledTime(Time::Draw.Time.GetTotalSeconds()) , Instanced(instanced) { } @@ -83,7 +83,7 @@ void IMaterial::BindParameters::BindViewData() cb.ViewFar = view.Far; cb.ViewDir = view.Direction; cb.TimeParam = Time; - cb.UnscaledTimeParam = UnscaledTime; + cb.ScaledTimeParam = ScaledTime; cb.ViewInfo = view.ViewInfo; cb.ScreenSize = view.ScreenSize; cb.TemporalAAJitter = view.TemporalAAJitter; diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index 117246671..5da4ee04f 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -10,7 +10,7 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 175 +#define MATERIAL_GRAPH_VERSION 178 class Material; class GPUShader; diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index 0dae6c93e..64dfe8303 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -2,6 +2,7 @@ #include "MaterialShaderFeatures.h" #include "Engine/Graphics/RenderTask.h" +#include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Renderer/ShadowsPass.h" @@ -24,18 +25,30 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, SpanFog) { cache->Fog->GetExponentialHeightFogData(view, data.ExponentialHeightFog); + VolumetricFogOptions volumetricFog; + cache->Fog->GetVolumetricFogOptions(volumetricFog); + if (volumetricFog.UseVolumetricFog() && params.RenderContext.Buffers->VolumetricFog) + volumetricFogTexture = params.RenderContext.Buffers->VolumetricFog->ViewVolume(); + else + data.ExponentialHeightFog.VolumetricFogMaxDistance = -1.0f; } else { data.ExponentialHeightFog.FogMinOpacity = 1.0f; + data.ExponentialHeightFog.FogDensity = 0.0f; + data.ExponentialHeightFog.FogCutoffDistance = 0.1f; + data.ExponentialHeightFog.StartDistance = 0.0f; data.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f; } + params.GPUContext->BindSR(volumetricFogTextureRegisterIndex, volumetricFogTexture); // Set directional light input if (cache->DirectionalLights.HasItems()) diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h index 25689e765..54b91af23 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h @@ -25,7 +25,7 @@ struct ForwardShadingFeature : MaterialShaderFeature { enum { MaxLocalLights = 4 }; - enum { SRVs = 4 }; + enum { SRVs = 5 }; PACK_STRUCT(struct Data { diff --git a/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp b/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp index c82dd7447..ee7a41853 100644 --- a/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp @@ -22,7 +22,7 @@ PACK_STRUCT(struct PostFxMaterialShaderData { Float4 TemporalAAJitter; Matrix InverseViewProjectionMatrix; Float3 ViewPadding0; - float UnscaledTimeParam; + float ScaledTimeParam; }); void PostFxMaterialShader::Bind(BindParameters& params) @@ -54,7 +54,7 @@ void PostFxMaterialShader::Bind(BindParameters& params) materialData->ViewFar = view.Far; materialData->ViewDir = view.Direction; materialData->TimeParam = params.Time; - materialData->UnscaledTimeParam = params.UnscaledTime; + materialData->ScaledTimeParam = params.ScaledTime; materialData->ViewInfo = view.ViewInfo; materialData->ScreenSize = view.ScreenSize; materialData->TemporalAAJitter = view.TemporalAAJitter; diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index d99e0f5d0..b6b455f20 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -76,7 +76,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) scaleX > 0.00001f ? 1.0f / scaleX : 0.0f, scaleY > 0.00001f ? 1.0f / scaleY : 0.0f, scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f); - materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; + materialData->WorldDeterminantSign = drawCall.WorldDeterminant ? -1.0f : 1.0f; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; materialData->CurrentLOD = drawCall.Terrain.CurrentLOD; materialData->ChunkSizeNextLOD = drawCall.Terrain.ChunkSizeNextLOD; @@ -109,13 +109,10 @@ void TerrainMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminant) { // Invert culling when scale is negative - if (cullMode == CullMode::Normal) - cullMode = CullMode::Inverted; - else - cullMode = CullMode::Normal; + cullMode = cullMode == CullMode::Normal ? CullMode::Inverted : CullMode::Normal; } const PipelineStateCache* psCache = _cache.GetPS(view.Pass, useLightmap); ASSERT(psCache); @@ -123,6 +120,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) // Bind pipeline context->SetState(state); + context->SetStencilRef(drawCall.StencilValue); } void TerrainMaterialShader::Unload() @@ -139,6 +137,10 @@ bool TerrainMaterialShader::Load() psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; + psDesc.StencilEnable = true; + psDesc.StencilReadMask = 0; + psDesc.StencilPassOp = StencilOperation::Replace; + #if GPU_ALLOW_TESSELLATION_SHADERS // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 32df730e8..c2f340645 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -218,7 +218,7 @@ bool Mesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const void* return Init(vertices, triangles, vbData, ib, use16BitIndexBuffer, vbLayout); } -void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int8 sortOrder) const +void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int8 sortOrder, uint8 stencilValue) const { if (!material || !material->IsSurface() || !IsInitialized()) return; @@ -240,8 +240,8 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons drawCall.ObjectRadius = (float)_sphere.Radius * drawCall.World.GetScaleVector().GetAbsolute().MaxValue(); drawCall.Surface.GeometrySize = _box.GetSize(); drawCall.Surface.PrevWorld = world; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = perInstanceRandom; + drawCall.StencilValue = stencilValue; #if USE_EDITOR const ViewMode viewMode = renderContext.View.Mode; if (viewMode == ViewMode::LightmapUVsDensity || viewMode == ViewMode::LODPreview) @@ -307,8 +307,8 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr; drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty; drawCall.Surface.LODDitherFactor = lodDitherFactor; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = info.PerInstanceRandom; + drawCall.StencilValue = info.StencilValue; #if USE_EDITOR const ViewMode viewMode = renderContext.View.Mode; if (viewMode == ViewMode::LightmapUVsDensity || viewMode == ViewMode::LODPreview) @@ -370,8 +370,8 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr; drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty; drawCall.Surface.LODDitherFactor = lodDitherFactor; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = info.PerInstanceRandom; + drawCall.StencilValue = info.StencilValue; #if USE_EDITOR const ViewMode viewMode = renderContextBatch.GetMainContext().View.Mode; if (viewMode == ViewMode::LightmapUVsDensity || viewMode == ViewMode::LODPreview) diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h index 63b069f9a..8e273a3d5 100644 --- a/Source/Engine/Graphics/Models/Mesh.h +++ b/Source/Engine/Graphics/Models/Mesh.h @@ -142,7 +142,8 @@ public: /// The draw passes to use for rendering this object. /// The random per-instance value (normalized to range 0-1). /// Object sorting key. - API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int8 sortOrder = 0) const; + /// Object stencil value. + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int8 sortOrder = 0, uint8 stencilValue = 0) const; /// /// Draws the mesh. diff --git a/Source/Engine/Graphics/Models/MeshBase.h b/Source/Engine/Graphics/Models/MeshBase.h index 6a61ec3a5..1c76df166 100644 --- a/Source/Engine/Graphics/Models/MeshBase.h +++ b/Source/Engine/Graphics/Models/MeshBase.h @@ -404,6 +404,11 @@ public: /// float PerInstanceRandom; + /// + /// The 8-bit stencil value to write into Depth-Stencil Buffer. + /// + uint8 StencilValue; + /// /// The LOD bias value. /// @@ -422,6 +427,12 @@ public: #if USE_EDITOR float LightmapScale = -1.0f; #endif + + // Packs object layer into the stencil bits. + FORCE_INLINE void SetStencilValue(int32 layer) + { + StencilValue = uint8(layer & 0x1f); + } }; /// diff --git a/Source/Engine/Graphics/Models/ModelData.cpp b/Source/Engine/Graphics/Models/ModelData.cpp index 877d8c826..69ae5d9a1 100644 --- a/Source/Engine/Graphics/Models/ModelData.cpp +++ b/Source/Engine/Graphics/Models/ModelData.cpp @@ -372,6 +372,8 @@ bool MaterialSlotEntry::UsesProperties() const Opacity.TextureIndex != -1 || Math::NotNearEqual(Roughness.Value, 0.5f) || Roughness.TextureIndex != -1 || + Math::NotNearEqual(Metalness.Value, 0.5f) || + Metalness.TextureIndex != -1 || Normals.TextureIndex != -1; } diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h index 8e401b973..26b473e09 100644 --- a/Source/Engine/Graphics/Models/ModelData.h +++ b/Source/Engine/Graphics/Models/ModelData.h @@ -327,14 +327,23 @@ struct FLAXENGINE_API MaterialSlotEntry { float Value = 0.5f; int32 TextureIndex = -1; + uint8 Channel = 0; } Roughness; + struct + { + float Value = 0.0f; + int32 TextureIndex = -1; + uint8 Channel = 0; + } Metalness; + struct { int32 TextureIndex = -1; } Normals; bool TwoSided = false; + bool Wireframe = false; bool UsesProperties() const; static float ShininessToRoughness(float shininess); @@ -434,7 +443,8 @@ public: { Float32, Float16, - } PositionFormat = PositionFormats::Float32; + Automatic, + } PositionFormat = PositionFormats::Automatic; // See ModelTool::TexCoordFormats enum class TexCoordFormats diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 8c1b98ebf..66b3e5701 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -314,8 +314,8 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info, drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; drawCall.Surface.Skinning = info.Skinning; drawCall.Surface.LODDitherFactor = lodDitherFactor; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = info.PerInstanceRandom; + drawCall.StencilValue = info.StencilValue; // Push draw call to the render list renderContext.List->AddDrawCall(renderContext, drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals, info.SortOrder); @@ -355,8 +355,8 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; drawCall.Surface.Skinning = info.Skinning; drawCall.Surface.LODDitherFactor = lodDitherFactor; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = info.PerInstanceRandom; + drawCall.StencilValue = info.StencilValue; // Push draw call to the render lists const auto shadowsMode = entry.ShadowsMode & slot.ShadowsMode; diff --git a/Source/Engine/Graphics/RenderBuffers.h b/Source/Engine/Graphics/RenderBuffers.h index 647d28c4c..dadd06175 100644 --- a/Source/Engine/Graphics/RenderBuffers.h +++ b/Source/Engine/Graphics/RenderBuffers.h @@ -13,6 +13,17 @@ #define GBUFFER2_FORMAT PixelFormat::R8G8B8A8_UNorm #define GBUFFER3_FORMAT PixelFormat::R8G8B8A8_UNorm +// Stencil bits usage (must match GBuffer.hlsl) +// [0] | Object Layer +// [1] | Object Layer +// [2] | Object Layer +// [3] | Object Layer +// [4] | Object Layer +// [5] | +// [6] | +// [7] | +#define STENCIL_BUFFER_OBJECT_LAYER(value) uint8(value & 0x1f) + /// /// The scene rendering buffers container. /// diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h index e7b60491c..a85480e3e 100644 --- a/Source/Engine/Graphics/RenderView.h +++ b/Source/Engine/Graphics/RenderView.h @@ -265,6 +265,14 @@ public: return Projection.M44 >= 1.0f; } + /// + /// Determines whether view Origin has been moved in this frame. Old history buffers/data might be invalid. + /// + FORCE_INLINE bool IsOriginTeleport() const + { + return Origin != PrevOrigin; + } + public: // Ignore deprecation warnings in defaults PRAGMA_DISABLE_DEPRECATION_WARNINGS diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h index 85ac4ae0b..184f50c89 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.h +++ b/Source/Engine/Graphics/Textures/GPUTexture.h @@ -437,6 +437,12 @@ public: /// The view to the depth-stencil resource descriptor as read-only depth. API_FUNCTION() virtual GPUTextureView* ViewReadOnlyDepth() const = 0; + /// + /// Gets the view to the texture as stencil buffer. + /// + /// The view to the stencil resource descriptor. + API_FUNCTION() virtual GPUTextureView* ViewStencil() const = 0; + /// /// Implicit conversion to the first surface (only for 2D textures). /// diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp index 2a50fbfd8..a0ec80bb1 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp @@ -11,6 +11,7 @@ #include "GPUSamplerDX11.h" #include "GPUVertexLayoutDX11.h" #include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h" +#include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Core/Math/Viewport.h" #include "Engine/Core/Math/Rectangle.h" #include "Engine/Profiler/RenderStats.h" @@ -216,7 +217,10 @@ void GPUContextDX11::ClearDepth(GPUTextureView* depthBuffer, float depthValue, u if (depthBufferDX11) { ASSERT(depthBufferDX11->DSV()); - _context->ClearDepthStencilView(depthBufferDX11->DSV(), D3D11_CLEAR_DEPTH, depthValue, stencilValue); + UINT clearFlags = D3D11_CLEAR_DEPTH; + if (PixelFormatExtensions::HasStencil(depthBufferDX11->GetFormat())) + clearFlags |= D3D11_CLEAR_STENCIL; + _context->ClearDepthStencilView(depthBufferDX11->DSV(), clearFlags, depthValue, stencilValue); } } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.cpp index e858f7e3e..a05585696 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.cpp @@ -150,6 +150,7 @@ void GPUTextureDX11::OnReleaseGPU() _handleArray.Release(); _handleVolume.Release(); _handleReadOnlyDepth.Release(); + _handleStencil.Release(); DX_SAFE_RELEASE_CHECK(_resource, 0); // Base @@ -547,6 +548,41 @@ void GPUTextureDX11::initHandles() } _handleReadOnlyDepth.Init(this, rtView, srView, dsView, nullptr, format, msaa); } + + // Stencil view + if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format)) + { + PixelFormat stencilFormat; + switch (_dxgiFormatDSV) + { + case PixelFormat::D24_UNorm_S8_UInt: + srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencilFormat = PixelFormat::X24_Typeless_G8_UInt; + break; + case PixelFormat::D32_Float_S8X24_UInt: + srDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt; + break; + } + if (isCubeMap) + { + srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srDesc.TextureCube.MostDetailedMip = 0; + srDesc.TextureCube.MipLevels = mipLevels; + } + else if (isMsaa) + { + srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + } + else + { + srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srDesc.Texture2D.MostDetailedMip = 0; + srDesc.Texture2D.MipLevels = mipLevels; + } + VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView)); + _handleStencil.Init(this, nullptr, srView, nullptr, nullptr, stencilFormat, msaa); + } } bool GPUTextureDX11::GetData(int32 arrayIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.h index d33c56158..35101e79b 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTextureDX11.h @@ -158,6 +158,7 @@ private: GPUTextureViewDX11 _handleArray; GPUTextureViewDX11 _handleVolume; GPUTextureViewDX11 _handleReadOnlyDepth; + GPUTextureViewDX11 _handleStencil; Array _handlesPerSlice; // [slice] Array> _handlesPerMip; // [slice][mip] @@ -225,6 +226,11 @@ public: ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView); return (GPUTextureView*)&_handleReadOnlyDepth; } + GPUTextureView* ViewStencil() const override + { + ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil); + return (GPUTextureView*)&_handleStencil; + } void* GetNativePtr() const override { return static_cast(_resource); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp index bb1eaacdb..0d9ff88d4 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp @@ -136,8 +136,13 @@ bool GPUBufferDX12::OnInit() // Create resource ID3D12Resource* resource; +#if PLATFORM_WINDOWS + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; +#else + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; +#endif D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; - VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, nullptr, IID_PPV_ARGS(&resource))); + VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(&heapProperties, heapFlags, &resourceDesc, initialState, nullptr, IID_PPV_ARGS(&resource))); // Set state initResource(resource, initialState, 1); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp index c68e7f262..64c384447 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp @@ -36,6 +36,7 @@ #include "CommandSignatureDX12.h" #include "Engine/Profiler/RenderStats.h" #include "Engine/Graphics/GPUResourceAccess.h" +#include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Graphics/Shaders/GPUShader.h" #include "Engine/Threading/Threading.h" @@ -823,7 +824,10 @@ void GPUContextDX12::ClearDepth(GPUTextureView* depthBuffer, float depthValue, u SetResourceState(depthBufferDX12->GetResourceOwner(), D3D12_RESOURCE_STATE_DEPTH_WRITE, depthBufferDX12->SubresourceIndex); flushRBs(); - _commandList->ClearDepthStencilView(depthBufferDX12->DSV(), D3D12_CLEAR_FLAG_DEPTH, depthValue, stencilValue, 0, nullptr); + D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH; + if (PixelFormatExtensions::HasStencil(depthBufferDX12->GetFormat())) + clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + _commandList->ClearDepthStencilView(depthBufferDX12->DSV(), clearFlags, depthValue, stencilValue, 0, nullptr); } } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index e140da37e..88334be60 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -307,6 +307,32 @@ bool GPUDeviceDX12::Init() LOG(Info, "Hardware Version: {0}", hwVer); updateFrameEvents(); + // Setup display output + auto& videoOutput = VideoOutputs.AddOne(); + videoOutput.Name = hwVer; + ComPtr dxgiDevice; + VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_GRAPHICS_PPV_ARGS(&dxgiDevice))); + ComPtr dxgiAdapter; + VALIDATE_DIRECTX_CALL(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf())); + ComPtr dxgiOutput; + VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf())); + DXGI_FORMAT backbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT); + UINT modesCount = 0; + VALIDATE_DIRECTX_CALL(dxgiOutput->GetDisplayModeList(backbufferFormat, 0, &modesCount, NULL)); + Array modes; + modes.Resize((int32)modesCount); + VALIDATE_DIRECTX_CALL(dxgiOutput->GetDisplayModeListX(backbufferFormat, 0, &modesCount, modes.Get())); + for (const DXGIXBOX_MODE_DESC& mode : modes) + { + if (mode.Width > videoOutput.Width) + { + videoOutput.Width = mode.Width; + videoOutput.Height = mode.Height; + } + videoOutput.RefreshRate = Math::Max(videoOutput.RefreshRate, mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator); + } + modes.Resize(0); + #if PLATFORM_GDK GDKPlatform::Suspended.Bind(this); GDKPlatform::Resumed.Bind(this); @@ -943,6 +969,7 @@ void GPUDeviceDX12::updateFrameEvents() dxgiAdapter->GetDesc(&_adapter->Description); ComPtr dxgiOutput; VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf())); + // TODO: support 120/40/30/24 fps VALIDATE_DIRECTX_CALL(_device->SetFrameIntervalX(dxgiOutput.Get(), D3D12XBOX_FRAME_INTERVAL_60_HZ, DX12_BACK_BUFFER_COUNT - 1u, D3D12XBOX_FRAME_INTERVAL_FLAG_NONE)); VALIDATE_DIRECTX_CALL(_device->ScheduleFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, 0U, nullptr, D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE)); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.cpp index c44d6f80d..e7e4c5ca2 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.cpp @@ -159,7 +159,12 @@ bool GPUTextureDX12::OnInit() initialState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; // Create texture - auto result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, initialState, clearValuePtr, IID_PPV_ARGS(&resource)); +#if PLATFORM_WINDOWS + D3D12_HEAP_FLAGS heapFlags = useRTV || useDSV ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE; +#else + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; +#endif + auto result = device->CreateCommittedResource(&heapProperties, heapFlags, &resourceDesc, initialState, clearValuePtr, IID_PPV_ARGS(&resource)); LOG_DIRECTX_RESULT_WITH_RETURN(result, true); // Set state @@ -226,6 +231,8 @@ void GPUTextureDX12::OnReleaseGPU() _handlesPerSlice.Resize(0, false); _handleArray.Release(); _handleVolume.Release(); + _handleReadOnlyDepth.Release(); + _handleStencil.Release(); _srv.Release(); _uav.Release(); releaseResource(); @@ -720,6 +727,45 @@ void GPUTextureDX12::initHandles() _handleReadOnlyDepth.SetSRV(srDesc); } } + + // Stencil view + if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format)) + { + PixelFormat stencilFormat; + switch (_dxgiFormatDSV) + { + case PixelFormat::D24_UNorm_S8_UInt: + srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT; + stencilFormat = PixelFormat::X24_Typeless_G8_UInt; + break; + case PixelFormat::D32_Float_S8X24_UInt: + srDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt; + break; + } + if (isCubeMap) + { + srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + srDesc.TextureCube.MostDetailedMip = 0; + srDesc.TextureCube.MipLevels = mipLevels; + srDesc.TextureCube.ResourceMinLODClamp = 0; + } + else if (isMsaa) + { + srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; + } + else + { + srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srDesc.Texture2D.MostDetailedMip = 0; + srDesc.Texture2D.MipLevels = mipLevels; + srDesc.Texture2D.ResourceMinLODClamp = 0; + srDesc.Texture2D.PlaneSlice = 1; + } + _handleStencil.Init(this, _device, this, stencilFormat, msaa); + _handleStencil.ReadOnlyDepthView = true; + _handleStencil.SetSRV(srDesc); + } } #endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.h index e6427ab6d..b513b5b4f 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUTextureDX12.h @@ -91,7 +91,7 @@ public: // [IShaderResourceDX12] bool IsDepthStencilResource() const override { - return _dsv.IsValid(); + return ReadOnlyDepthView || _dsv.IsValid(); } D3D12_CPU_DESCRIPTOR_HANDLE SRV() const override { @@ -117,6 +117,7 @@ private: GPUTextureViewDX12 _handleArray; GPUTextureViewDX12 _handleVolume; GPUTextureViewDX12 _handleReadOnlyDepth; + GPUTextureViewDX12 _handleStencil; Array _handlesPerSlice; // [slice] Array> _handlesPerMip; // [slice][mip] @@ -165,6 +166,11 @@ public: ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView); return (GPUTextureView*)&_handleReadOnlyDepth; } + GPUTextureView* ViewStencil() const override + { + ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil); + return (GPUTextureView*)&_handleStencil; + } void* GetNativePtr() const override { return (void*)_resource; diff --git a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp index f195b8b41..7e38ecadb 100644 --- a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.cpp @@ -7,6 +7,7 @@ #include "GPUDeviceDX.h" #include "Engine/Core/Types/DateTime.h" #include "Engine/Core/Types/StringBuilder.h" +#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Graphics/GPUDevice.h" #include "IncludeDirectXHeaders.h" #include @@ -21,6 +22,9 @@ typedef void* LPCDLGTEMPLATE; #pragma comment(lib, "SetupAPI.lib") #endif +#define DISPLAY_DEVICE_ACTIVE 0x00000001 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 + namespace Windows { typedef struct _devicemodeW @@ -84,7 +88,18 @@ namespace Windows DWORD dmPanningHeight; } DEVMODEW, *PDEVMODEW, *NPDEVMODEW, *LPDEVMODEW; + typedef struct _DISPLAY_DEVICEW + { + DWORD cb; + WCHAR DeviceName[32]; + WCHAR DeviceString[128]; + DWORD StateFlags; + WCHAR DeviceID[128]; + WCHAR DeviceKey[128]; + } DISPLAY_DEVICEW, *PDISPLAY_DEVICEW, *LPDISPLAY_DEVICEW; + WIN_API BOOL WIN_API_CALLCONV EnumDisplaySettingsW(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode); + WIN_API BOOL WIN_API_CALLCONV EnumDisplayDevicesW(LPCWSTR lpDevice, DWORD iDevNum, PDISPLAY_DEVICEW lpDisplayDevice, DWORD dwFlags); } // @formatter:off @@ -590,13 +605,14 @@ void GPUAdapterDX::SetDriverVersion(Version& ver) DriverVersion = ver; } +#if PLATFORM_WINDOWS + void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter) { -#if PLATFORM_WINDOWS - // Collect output devices + PROFILE_CPU(); uint32 outputIdx = 0; ComPtr output; - DXGI_FORMAT defaultBackbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT); + DXGI_FORMAT backbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT); Array modeDesc; while (adapter->EnumOutputs(outputIdx, &output) != DXGI_ERROR_NOT_FOUND) { @@ -606,7 +622,7 @@ void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter) output->GetDesc(&outputDX11.Desc); uint32 numModes = 0; - HRESULT hr = output->GetDisplayModeList(defaultBackbufferFormat, 0, &numModes, nullptr); + HRESULT hr = output->GetDisplayModeList(backbufferFormat, 0, &numModes, nullptr); if (FAILED(hr)) { LOG(Warning, "Error while enumerating adapter output video modes."); @@ -614,7 +630,7 @@ void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter) } modeDesc.Resize(numModes, false); - hr = output->GetDisplayModeList(defaultBackbufferFormat, 0, &numModes, modeDesc.Get()); + hr = output->GetDisplayModeList(backbufferFormat, 0, &numModes, modeDesc.Get()); if (FAILED(hr)) { LOG(Warning, "Error while enumerating adapter output video modes."); @@ -635,16 +651,10 @@ void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter) break; } } - if (!foundVideoMode) { outputDX11.VideoModes.Add(mode); - - // Collect only from the main monitor - if (Outputs.Count() == 1) - { - VideoOutputModes.Add({ mode.Width, mode.Height, (uint32)(mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator) }); - } + VideoOutputModes.Add({ mode.Width, mode.Height, mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator, VideoOutputs.Count() }); } } @@ -659,24 +669,57 @@ void GPUDeviceDX::UpdateOutputs(IDXGIAdapter* adapter) devMode.dmDriverExtra = 0; Windows::EnumDisplaySettingsW(monitorInfo.szDevice, ((DWORD)-1), &devMode); + // Initialize display mode for Desktop DXGI_MODE_DESC currentMode; currentMode.Width = devMode.dmPelsWidth; currentMode.Height = devMode.dmPelsHeight; bool useDefaultRefreshRate = 1 == devMode.dmDisplayFrequency || 0 == devMode.dmDisplayFrequency; currentMode.RefreshRate.Numerator = useDefaultRefreshRate ? 0 : devMode.dmDisplayFrequency; currentMode.RefreshRate.Denominator = useDefaultRefreshRate ? 0 : 1; - currentMode.Format = defaultBackbufferFormat; + currentMode.Format = backbufferFormat; currentMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; currentMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - if (output->FindClosestMatchingMode(¤tMode, &outputDX11.DesktopViewMode, nullptr) != S_OK) outputDX11.DesktopViewMode = currentMode; - float refreshRate = outputDX11.DesktopViewMode.RefreshRate.Numerator / (float)outputDX11.DesktopViewMode.RefreshRate.Denominator; - LOG(Info, "Video output '{0}' {1}x{2} {3} Hz", outputDX11.Desc.DeviceName, devMode.dmPelsWidth, devMode.dmPelsHeight, refreshRate); + // Add video output + auto& videoOutput = VideoOutputs.AddOne(); + videoOutput.Width = devMode.dmPelsWidth; + videoOutput.Height = devMode.dmPelsHeight; + videoOutput.RefreshRate = outputDX11.DesktopViewMode.RefreshRate.Numerator / (float)outputDX11.DesktopViewMode.RefreshRate.Denominator; + + // Query display device name + Windows::DISPLAY_DEVICEW displayDevice; + displayDevice.cb = sizeof(displayDevice); + DWORD monitorIndex = 0; + while (Windows::EnumDisplayDevicesW(outputDX11.Desc.DeviceName, monitorIndex, &displayDevice, 0)) + { + if (displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE && !(displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) + { + StringView id(displayDevice.DeviceID); + videoOutput.Name = id.Substring(8, id.Substring(9).Find(TEXT('\\')) + 1); + break; + } + monitorIndex++; + } + if (videoOutput.Name.IsEmpty()) + videoOutput.Name = outputDX11.Desc.DeviceName; + +#ifdef __IDXGIOutput6_INTERFACE_DEFINED__ + // Query HDR support + ComPtr output6; + if (SUCCEEDED(output->QueryInterface(IID_PPV_ARGS(&output6)))) + { + DXGI_OUTPUT_DESC1 outputDesc; + output6->GetDesc1(&outputDesc); + videoOutput.HDR = outputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + } +#endif + outputIdx++; } -#endif } #endif + +#endif diff --git a/Source/Engine/GraphicsDevice/Null/GPUTextureNull.h b/Source/Engine/GraphicsDevice/Null/GPUTextureNull.h index 25b204184..23e7d2b54 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUTextureNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUTextureNull.h @@ -33,6 +33,10 @@ public: { return nullptr; } + GPUTextureView* ViewStencil() const override + { + return nullptr; + } void* GetNativePtr() const override { return nullptr; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index 2db4e202a..2afb18349 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -1388,7 +1388,7 @@ void GPUContextVulkan::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 } else { - auto allocation = _device->UploadBuffer.Upload(data, size, 4); + auto allocation = _device->UploadBuffer.Upload(data, size, PLATFORM_MEMORY_ALIGNMENT); VkBufferCopy region; region.size = size; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp index 326c87e8d..52f347959 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.cpp @@ -11,7 +11,7 @@ #include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Scripting/Enums.h" -void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels, int32 firstMipIndex, int32 arraySize, int32 firstArraySlice, bool readOnlyDepth) +void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels, int32 firstMipIndex, int32 arraySize, int32 firstArraySlice, bool readOnlyDepth, bool stencilView) { ASSERT(View == VK_NULL_HANDLE); @@ -57,7 +57,13 @@ void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* ow SubresourceIndex = RenderTools::CalcSubresourceIndex(firstMipIndex, firstArraySlice, totalMipLevels); } - if (PixelFormatExtensions::IsDepthStencil(format)) + if (stencilView) + { + range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + LayoutRTV = readOnlyDepth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + LayoutSRV = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + else if (PixelFormatExtensions::IsDepthStencil(format)) { range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; #if 0 @@ -157,13 +163,23 @@ void GPUTextureViewVulkan::DescriptorAsImage(GPUContextVulkan* context, VkImageV imageView = View; layout = LayoutSRV; const VkImageAspectFlags aspectMask = Info.subresourceRange.aspectMask; - if (aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) + if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - // Transition depth-only when binding depth buffer with stencil + // Transition depth-only when binding depth buffer with stencil (or stencil-only without depth) if (ViewSRV == VK_NULL_HANDLE) { VkImageViewCreateInfo createInfo = Info; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) + { + // Stencil + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + createInfo.components.g = VK_COMPONENT_SWIZZLE_R; // Map .g component in shader to .r of stencil plane + } + else + { + // Depth + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } VALIDATE_VULKAN_RESULT(vkCreateImageView(Device->Device, &createInfo, nullptr, &ViewSRV)); } imageView = ViewSRV; @@ -434,6 +450,26 @@ void GPUTextureVulkan::initHandles() { _handleReadOnlyDepth.Init(_device, this, _image, mipLevels, format, msaa, extent, VK_IMAGE_VIEW_TYPE_2D, mipLevels, 0, 1, 0, true); } + + // Stencil view + if (IsDepthStencil() && IsShaderResource() && PixelFormatExtensions::HasStencil(format)) + { + PixelFormat stencilFormat; + switch (format) + { + case PixelFormat::D24_UNorm_S8_UInt: + case PixelFormat::R24_UNorm_X8_Typeless: + case PixelFormat::R24G8_Typeless: + stencilFormat = PixelFormat::X24_Typeless_G8_UInt; + break; + case PixelFormat::D32_Float_S8X24_UInt: + case PixelFormat::R32_Float_X8X24_Typeless: + case PixelFormat::R32G8X24_Typeless: + stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt; + break; + } + _handleStencil.Init(_device, this, _image, mipLevels, stencilFormat, msaa, extent, VK_IMAGE_VIEW_TYPE_2D, mipLevels, 0, 1, 0, true, true); + } } void GPUTextureVulkan::OnResidentMipsChanged() @@ -457,6 +493,7 @@ void GPUTextureVulkan::OnReleaseGPU() _handleVolume.Release(); _handleUAV.Release(); _handleReadOnlyDepth.Release(); + _handleStencil.Release(); for (int32 i = 0; i < _handlesPerMip.Count(); i++) { for (int32 j = 0; j < _handlesPerMip[i].Count(); j++) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.h index 999e0f602..178938b82 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUTextureVulkan.h @@ -45,7 +45,7 @@ public: #endif public: - void Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels = 1, int32 firstMipIndex = 0, int32 arraySize = 1, int32 firstArraySlice = 0, bool readOnlyDepth = false); + void Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels = 1, int32 firstMipIndex = 0, int32 arraySize = 1, int32 firstArraySlice = 0, bool readOnlyDepth = false, bool stencilView = false); VkImageView GetFramebufferView(); @@ -79,6 +79,7 @@ private: GPUTextureViewVulkan _handleVolume; GPUTextureViewVulkan _handleUAV; GPUTextureViewVulkan _handleReadOnlyDepth; + GPUTextureViewVulkan _handleStencil; Array _handlesPerSlice; // [slice] Array> _handlesPerMip; // [slice][mip] @@ -140,6 +141,11 @@ public: ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView); return (GPUTextureView*)&_handleReadOnlyDepth; } + GPUTextureView* ViewStencil() const override + { + ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil); + return (GPUTextureView*)&_handleStencil; + } void* GetNativePtr() const override { return (void*)_image; diff --git a/Source/Engine/GraphicsDevice/Vulkan/UploadBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/UploadBufferVulkan.cpp index 15b58a8b4..3a0258c8c 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/UploadBufferVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/UploadBufferVulkan.cpp @@ -111,6 +111,7 @@ UploadBufferVulkan::Allocation UploadBufferVulkan::Allocate(uint64 size, uint64 // Move within a page _currentOffset += size; + ASSERT_LOW_LAYER(_currentOffset <= _currentPage->Size); return result; } diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 551f6fba9..7d07cd0e7 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -1185,14 +1185,11 @@ void Actor::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) } else if (!parent && parentId.IsValid()) { + Guid tmpId; if (_prefabObjectID.IsValid()) - { LOG(Warning, "Missing parent actor {0} for \'{1}\', prefab object {2}", parentId, ToString(), _prefabObjectID); - } - else - { + else if (!modifier->IdsMapping.TryGet(parentId, tmpId) || tmpId.IsValid()) // Skip warning if object was mapped to empty id (intentionally ignored) LOG(Warning, "Missing parent actor {0} for \'{1}\'", parentId, ToString()); - } } } } @@ -1757,7 +1754,7 @@ bool Actor::ToBytes(const Array& actors, MemoryWriteStream& output) } // Collect object ids that exist in the serialized data to allow references mapping later - Array ids(Math::RoundUpToPowerOf2(actors.Count() * 2)); + Array ids(actors.Count()); for (int32 i = 0; i < actors.Count(); i++) { // By default we collect actors and scripts (they are ManagedObjects recognized by the id) @@ -2060,19 +2057,27 @@ Actor* Actor::Clone() // Remap object ids into a new ones auto modifier = Cache::ISerializeModifier.Get(); - for (int32 i = 0; i < actors->Count(); i++) + for (const Actor* actor : *actors.Value) { - auto actor = actors->At(i); if (!actor) continue; modifier->IdsMapping.Add(actor->GetID(), Guid::New()); - for (int32 j = 0; j < actor->Scripts.Count(); j++) + for (const Script* script : actor->Scripts) { - const auto script = actor->Scripts[j]; if (script) modifier->IdsMapping.Add(script->GetID(), Guid::New()); } } + if (HasPrefabLink() && HasParent() && !IsPrefabRoot()) + { + // When cloning actor that is part of prefab (but not as whole), ignore the prefab hierarchy + Actor* parent = GetParent(); + do + { + modifier->IdsMapping.Add(parent->GetPrefabObjectID(), Guid::Empty); + parent = parent->GetParent(); + } while (parent && !parent->IsPrefabRoot()); + } // Deserialize objects Array output; diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 18342dbbb..ee66c6c77 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -1027,6 +1027,7 @@ void AnimatedModel::Draw(RenderContext& renderContext) draw.LODBias = LODBias; draw.ForcedLOD = ForcedLOD; draw.SortOrder = SortOrder; + draw.SetStencilValue(_layer); SkinnedModel->Draw(renderContext, draw); } @@ -1068,6 +1069,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) draw.LODBias = LODBias; draw.ForcedLOD = ForcedLOD; draw.SortOrder = SortOrder; + draw.SetStencilValue(_layer); PRAGMA_DISABLE_DEPRECATION_WARNINGS if (ShadowsMode != ShadowsCastingMode::All) diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 490f9d786..4a7d2aa75 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -374,6 +374,7 @@ void Camera::Draw(RenderContext& renderContext) BoundingSphere::FromBox(_previewModelBox, draw.Bounds); draw.Bounds.Center -= renderContext.View.Origin; draw.PerInstanceRandom = GetPerInstanceRandom(); + draw.StencilValue = 0; draw.LODBias = 0; draw.ForcedLOD = -1; draw.SortOrder = 0; diff --git a/Source/Engine/Level/Actors/Decal.cpp b/Source/Engine/Level/Actors/Decal.cpp index 82661b131..78066133c 100644 --- a/Source/Engine/Level/Actors/Decal.cpp +++ b/Source/Engine/Level/Actors/Decal.cpp @@ -87,6 +87,7 @@ void Decal::Draw(RenderContext& renderContext) transform.Scale *= _size; renderContext.View.GetWorldMatrix(transform, data.World); data.SortOrder = SortOrder; + data.RenderLayersMask = RenderLayersMask; data.Material = material; renderContext.List->Decals.Add(data); } @@ -102,6 +103,7 @@ void Decal::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Material); SERIALIZE_MEMBER(Size, _size); SERIALIZE(SortOrder); + SERIALIZE(RenderLayersMask); SERIALIZE(DrawMinScreenSize); } @@ -113,6 +115,7 @@ void Decal::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) DESERIALIZE(Material); DESERIALIZE_MEMBER(Size, _size); DESERIALIZE(SortOrder); + DESERIALIZE(RenderLayersMask); DESERIALIZE(DrawMinScreenSize); _bounds.Extents = _size * 0.5f; diff --git a/Source/Engine/Level/Actors/Decal.h b/Source/Engine/Level/Actors/Decal.h index 3adfdcbac..068a4447e 100644 --- a/Source/Engine/Level/Actors/Decal.h +++ b/Source/Engine/Level/Actors/Decal.h @@ -3,6 +3,7 @@ #pragma once #include "../Actor.h" +#include "Engine/Core/Types/LayersMask.h" #include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Content/Assets/MaterialBase.h" @@ -33,6 +34,12 @@ public: API_FIELD(Attributes="EditorOrder(20), EditorDisplay(\"Decal\")") int32 SortOrder = 0; + /// + /// The layers mask used for render composition. Can be used to include or exclude specific actor layers from the drawing on top of them. + /// + API_FIELD(Attributes = "EditorOrder(25), EditorDisplay(\"Decal\")") + LayersMask RenderLayersMask; + /// /// The minimum screen size for the decal drawing. If the decal size on the screen is smaller than this value then decal will be culled. Set it to higher value to make culling more aggressive. /// diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h index 08d311b6d..0e2a441db 100644 --- a/Source/Engine/Level/Actors/Light.h +++ b/Source/Engine/Level/Actors/Light.h @@ -63,7 +63,8 @@ protected: { const float dst2 = (float)Vector3::DistanceSquared(viewPosition, position); const float dst = Math::Sqrt(dst2); - brightness *= Math::Remap(dst, 0.9f * ViewDistance, ViewDistance, 1.0f, 0.0f); + if (dst < ViewDistance && dst > ViewDistance * 0.9f) + brightness *= Math::Remap(dst, 0.9f * ViewDistance, ViewDistance, 1.0f, 0.0f); return dst < ViewDistance; } return true; diff --git a/Source/Engine/Level/Actors/PointLight.cpp b/Source/Engine/Level/Actors/PointLight.cpp index d28ee3f16..607bf1bc4 100644 --- a/Source/Engine/Level/Actors/PointLight.cpp +++ b/Source/Engine/Level/Actors/PointLight.cpp @@ -19,7 +19,6 @@ PointLight::PointLight(const SpawnParams& params) _direction = Float3::Forward; _sphere = BoundingSphere(Vector3::Zero, _radius); BoundingBox::FromSphere(_sphere, _box); - _drawCategory = SceneRendering::SceneDrawAsync; } float PointLight::ComputeBrightness() const diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index 2ed6a9221..6d7d5efe2 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -21,7 +21,8 @@ #endif GPU_CB_STRUCT(Data { - Matrix WVP; + Matrix WorldViewProjection; + Matrix InvViewProjection; Float3 ViewOffset; float Padding; ShaderGBufferData GBuffer; @@ -30,8 +31,6 @@ GPU_CB_STRUCT(Data { Sky::Sky(const SpawnParams& params) : Actor(params) - , _psSky(nullptr) - , _psFog(nullptr) { _drawNoCulling = 1; _drawCategory = SceneRendering::PreRender; @@ -51,7 +50,6 @@ Sky::Sky(const SpawnParams& params) Sky::~Sky() { SAFE_DELETE_GPU_RESOURCE(_psSky); - SAFE_DELETE_GPU_RESOURCE(_psFog); } void Sky::InitConfig(ShaderAtmosphericFogData& config) const @@ -90,7 +88,7 @@ void Sky::Draw(RenderContext& renderContext) if (HasContentLoaded() && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { // Ensure to have pipeline state cache created - if (_psSky == nullptr || _psFog == nullptr) + if (_psSky == nullptr) { const auto shader = _shader->GetShader(); @@ -112,21 +110,6 @@ void Sky::Draw(RenderContext& renderContext) LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString()); } } - if (_psFog == nullptr) - { - _psFog = GPUDevice::Instance->CreatePipelineState(); - - GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; - psDesc.PS = shader->GetPS("PS_Fog"); - psDesc.DepthWriteEnable = false; - psDesc.DepthClipEnable = false; - psDesc.BlendMode = BlendingMode::Additive; - - if (_psFog->Init(psDesc)) - { - LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString()); - } - } } // Register for the sky and fog pass @@ -138,7 +121,6 @@ void Sky::Draw(RenderContext& renderContext) void Sky::Serialize(SerializeStream& stream, const void* otherObj) { - // Base Actor::Serialize(stream, otherObj); SERIALIZE_GET_OTHER_OBJ(Sky); @@ -151,7 +133,6 @@ void Sky::Serialize(SerializeStream& stream, const void* otherObj) void Sky::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { - // Base Actor::Deserialize(stream, modifier); DESERIALIZE_MEMBER(Sun, SunLight); @@ -172,40 +153,7 @@ bool Sky::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) void Sky::DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureView* output) { - // Get precomputed cache and bind it to the pipeline - AtmosphereCache cache; - if (!AtmospherePreCompute::GetCache(&cache)) - return; - PROFILE_GPU_CPU("Sky Fog"); - context->BindSR(4, cache.Transmittance); - context->BindSR(5, cache.Irradiance); - context->BindSR(6, cache.Inscatter->ViewVolume()); - - // Bind GBuffer inputs - context->BindSR(0, renderContext.Buffers->GBuffer0); - context->BindSR(1, renderContext.Buffers->GBuffer1); - context->BindSR(2, renderContext.Buffers->GBuffer2); - context->BindSR(3, renderContext.Buffers->DepthBuffer); - - // Setup constants data - Data data; - GBufferPass::SetInputs(renderContext.View, data.GBuffer); - data.ViewOffset = renderContext.View.Origin + GetPosition(); - InitConfig(data.Fog); - data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; - bool useSpecularLight = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::SpecularLight); - if (!useSpecularLight) - { - data.Fog.AtmosphericFogSunDiscScale = 0; - } - - // Bind pipeline - auto cb = _shader->GetShader()->GetCB(0); - context->UpdateCB(cb, &data); - context->BindCB(0, cb); - context->SetState(_psFog); - context->SetRenderTarget(output); - context->DrawFullscreenTriangle(); + MISSING_CODE("sky fog"); } bool Sky::IsDynamicSky() const @@ -231,14 +179,14 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr // Setup constants data Matrix m; Data data; - Matrix::Multiply(world, renderContext.View.Frustum.GetMatrix(), m); - Matrix::Transpose(m, data.WVP); + Matrix::Multiply(world, renderContext.View.ViewProjection(), m); + Matrix::Transpose(m, data.WorldViewProjection); + Matrix::Transpose(renderContext.View.IVP, data.InvViewProjection); GBufferPass::SetInputs(renderContext.View, data.GBuffer); data.ViewOffset = renderContext.View.Origin + GetPosition(); InitConfig(data.Fog); //data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; - bool useSpecularLight = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::SpecularLight); - if (!useSpecularLight) + if (EnumHasNoneFlags(renderContext.View.Flags, ViewFlags::SpecularLight)) { // Hide sun disc if specular light is disabled data.Fog.AtmosphericFogSunDiscScale = 0; @@ -253,11 +201,8 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr void Sky::EndPlay() { - // Cleanup SAFE_DELETE_GPU_RESOURCE(_psSky); - SAFE_DELETE_GPU_RESOURCE(_psFog); - // Base Actor::EndPlay(); } @@ -268,7 +213,6 @@ void Sky::OnEnable() GetSceneRendering()->AddViewportIcon(this); #endif - // Base Actor::OnEnable(); } @@ -279,13 +223,11 @@ void Sky::OnDisable() #endif GetSceneRendering()->RemoveActor(this, _sceneRenderingKey); - // Base Actor::OnDisable(); } void Sky::OnTransformChanged() { - // Base Actor::OnTransformChanged(); _box = BoundingBox(_transform.Translation); diff --git a/Source/Engine/Level/Actors/Sky.h b/Source/Engine/Level/Actors/Sky.h index 65bcc631a..61bb048ef 100644 --- a/Source/Engine/Level/Actors/Sky.h +++ b/Source/Engine/Level/Actors/Sky.h @@ -20,8 +20,7 @@ class FLAXENGINE_API Sky : public Actor, public IAtmosphericFogRenderer, public DECLARE_SCENE_OBJECT(Sky); private: AssetReference _shader; - GPUPipelineState* _psSky; - GPUPipelineState* _psFog; + GPUPipelineState* _psSky = nullptr; int32 _sceneRenderingKey = -1; public: @@ -57,7 +56,6 @@ private: void OnShaderReloading(Asset* obj) { _psSky = nullptr; - _psFog = nullptr; } #endif void InitConfig(ShaderAtmosphericFogData& config) const; diff --git a/Source/Engine/Level/Actors/Skybox.cpp b/Source/Engine/Level/Actors/Skybox.cpp index 6bfc98723..dbda65d3f 100644 --- a/Source/Engine/Level/Actors/Skybox.cpp +++ b/Source/Engine/Level/Actors/Skybox.cpp @@ -107,7 +107,6 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)_sphere.Radius; drawCall.Surface.GeometrySize = _box.GetSize(); - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = GetPerInstanceRandom(); MaterialBase::BindParameters bindParams(context, renderContext, drawCall); bindParams.BindViewData(); @@ -129,6 +128,7 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M material->SetParameterValue(TEXT("PanoramicTexture"), PanoramicTexture.Get(), false); material->SetParameterValue(TEXT("Color"), Color * Math::Exp2(Exposure), false); material->SetParameterValue(TEXT("IsPanoramic"), PanoramicTexture != nullptr, false); + material->SetParameterValue(TEXT("RotationEuler"), _rotationEuler, false); material->Bind(bindParams); } } @@ -163,4 +163,5 @@ void Skybox::OnTransformChanged() _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); + _rotationEuler = GetOrientation().GetEuler() * DegreesToRadians; } diff --git a/Source/Engine/Level/Actors/Skybox.h b/Source/Engine/Level/Actors/Skybox.h index f571a211f..fb831df44 100644 --- a/Source/Engine/Level/Actors/Skybox.h +++ b/Source/Engine/Level/Actors/Skybox.h @@ -18,6 +18,7 @@ class FLAXENGINE_API Skybox : public Actor, public ISkyRenderer private: AssetReference _proxyMaterial; int32 _sceneRenderingKey = -1; + Float3 _rotationEuler; public: /// diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index 8680fb8d5..42b2dc620 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -407,12 +407,12 @@ void SplineModel::Draw(RenderContext& renderContext) drawCall.Deformable.MeshMaxZ = _meshMaxZ; drawCall.Deformable.GeometrySize = _box.GetSize(); drawCall.PerInstanceRandom = GetPerInstanceRandom(); + drawCall.SetStencilValue(_layer); _preTransform.GetWorld(drawCall.Deformable.LocalMatrix); const Transform splineTransform = GetTransform(); renderContext.View.GetWorldMatrix(splineTransform, drawCall.World); drawCall.ObjectPosition = drawCall.World.GetTranslation() + drawCall.Deformable.LocalMatrix.GetTranslation(); drawCall.ObjectRadius = (float)_sphere.Radius; // TODO: use radius for the spline chunk rather than whole spline - const float worldDeterminantSign = drawCall.World.RotDeterminant() * drawCall.Deformable.LocalMatrix.RotDeterminant(); for (int32 segment = 0; segment < _instances.Count(); segment++) { auto& instance = _instances[segment]; @@ -468,7 +468,6 @@ void SplineModel::Draw(RenderContext& renderContext) // Submit draw call mesh->GetDrawCallGeometry(drawCall); drawCall.Material = material; - drawCall.WorldDeterminantSign = Math::FloatSelect(worldDeterminantSign * instance.RotDeterminant, 1, -1); renderContext.List->AddDrawCall(renderContext, drawModes, _staticFlags, drawCall, entry.ReceiveDecals); } } diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp index af783ce84..85b77647a 100644 --- a/Source/Engine/Level/Actors/SpotLight.cpp +++ b/Source/Engine/Level/Actors/SpotLight.cpp @@ -27,7 +27,6 @@ SpotLight::SpotLight(const SpawnParams& params) const float boundsRadius = Math::Sqrt(1.25f * _radius * _radius - _radius * _radius * _cosOuterCone); _sphere = BoundingSphere(GetPosition() + 0.5f * GetDirection() * _radius, boundsRadius); BoundingBox::FromSphere(_sphere, _box); - _drawCategory = SceneRendering::SceneDrawAsync; } float SpotLight::ComputeBrightness() const diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 912009b3b..f41e4a805 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -361,6 +361,7 @@ void StaticModel::Draw(RenderContext& renderContext) draw.ForcedLOD = _forcedLod; draw.SortOrder = _sortOrder; draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr; + draw.SetStencilValue(_layer); #if USE_EDITOR if (HasStaticFlag(StaticFlags::Lightmap)) draw.LightmapScale = _scaleInLightmap; @@ -397,6 +398,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch) draw.ForcedLOD = _forcedLod; draw.SortOrder = _sortOrder; draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr; + draw.SetStencilValue(_layer); #if USE_EDITOR if (HasStaticFlag(StaticFlags::Lightmap)) draw.LightmapScale = _scaleInLightmap; diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index fac756af8..dc3a57ea8 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -191,20 +191,25 @@ void SceneRendering::AddActor(Actor* a, int32& key) void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags) { const int32 category = a->_drawCategory; - ScopeReadLock lock(Locker); // Read-access only as list doesn't get resized (like Add/Remove do) so allow updating actors from different threads at once + bool lock = !_isRendering || ((int32)flags & (int32)ISceneRenderingListener::AutoDelayDuringRendering) == 0; // Allow updating actors during rendering + if (lock) + Locker.ReadLock(); // Read-access only as list doesn't get resized (like Add/Remove do) so allow updating actors from different threads at once auto& list = Actors[category]; - if (list.Count() <= key || key < 0) // Ignore invalid key softly - return; - auto& e = list[key]; - if (e.Actor == a) + if (list.Count() > key && key >= 0) // Ignore invalid key softly { - for (auto* listener : _listeners) - listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags); - if (flags & ISceneRenderingListener::Layer) - e.LayerMask = a->GetLayerMask(); - if (flags & ISceneRenderingListener::Bounds) - e.Bounds = a->GetSphere(); + auto& e = list[key]; + if (e.Actor == a) + { + for (auto* listener : _listeners) + listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags); + if (flags & ISceneRenderingListener::Layer) + e.LayerMask = a->GetLayerMask(); + if (flags & ISceneRenderingListener::Bounds) + e.Bounds = a->GetSphere(); + } } + if (lock) + Locker.ReadUnlock(); } void SceneRendering::RemoveActor(Actor* a, int32& key) diff --git a/Source/Engine/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index c11c94de8..25dfc63fa 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -55,6 +55,7 @@ public: Bounds = 2, Layer = 4, StaticFlags = 8, + AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked Auto = Visual | Bounds | Layer, }; @@ -68,6 +69,8 @@ public: virtual void OnSceneRenderingClear(SceneRendering* scene) = 0; }; +DECLARE_ENUM_OPERATORS(ISceneRenderingListener::UpdateFlags); + /// /// Scene rendering helper subsystem that boosts the level rendering by providing efficient objects cache and culling implementation. /// diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 7e9978635..9db851996 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -69,7 +69,7 @@ API_STRUCT(NoDefault, Namespace="FlaxEngine.Networking") struct FLAXENGINE_API N API_FIELD() uint64 Word1 = 0; // All bits set for all clients. - API_FIELD() static NetworkClientsMask All; + API_FIELD(ReadOnly) static NetworkClientsMask All; FORCE_INLINE bool HasBit(int32 bitIndex) const { diff --git a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp index 820f8da3d..ed4f5f0e3 100644 --- a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp +++ b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp @@ -246,6 +246,8 @@ void ParticleEmitterGPUGenerator::ProcessGroupTextures(Box* box, Node* node, Val break; } case MaterialSceneTextures::WorldPosition: + case MaterialSceneTextures::SceneStencil: + case MaterialSceneTextures::ObjectLayer: value = Value::Zero; // Not implemented break; default: diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp index 80738e65d..f4c883e20 100644 --- a/Source/Engine/Particles/ParticleEmitter.cpp +++ b/Source/Engine/Particles/ParticleEmitter.cpp @@ -106,7 +106,6 @@ namespace Asset::LoadResult ParticleEmitter::load() { PROFILE_MEM(Particles); - ScopeWriteLock systemScope(Particles::SystemLocker); // Load the graph const auto surfaceChunk = GetChunk(SHADER_FILE_CHUNK_VISJECT_SURFACE); @@ -330,8 +329,6 @@ Asset::LoadResult ParticleEmitter::load() // Wait for resources used by the emitter to be loaded // eg. texture used to place particles on spawn needs to be available - // Free Particles::SystemLocker when waiting on asset load to prevent lock-contention. - bool waitForAsset = false; for (const auto& node : Graph.Nodes) { if ((node.Type == GRAPH_NODE_MAKE_TYPE(5, 1) || node.Type == GRAPH_NODE_MAKE_TYPE(5, 2)) && node.Assets.Count() > 0) @@ -339,11 +336,6 @@ Asset::LoadResult ParticleEmitter::load() const auto texture = node.Assets[0].As(); if (texture) { - if (!waitForAsset) - { - waitForAsset = true; - Particles::SystemLocker.WriteUnlock(); - } WaitForAsset(texture); } } @@ -352,16 +344,9 @@ Asset::LoadResult ParticleEmitter::load() { if (parameter.Type.Type == VariantType::Asset) { - if (!waitForAsset) - { - waitForAsset = true; - Particles::SystemLocker.WriteUnlock(); - } WaitForAsset((Asset*)parameter.Value); } } - if (waitForAsset) - Particles::SystemLocker.WriteLock(); return LoadResult::Ok; } @@ -459,7 +444,6 @@ bool ParticleEmitter::SaveSurface(const BytesContainer& data) { if (OnCheckSave()) return true; - ScopeWriteLock systemScope(Particles::SystemLocker); ScopeLock lock(Locker); // Release all chunks diff --git a/Source/Engine/Particles/ParticleEmitterFunction.cpp b/Source/Engine/Particles/ParticleEmitterFunction.cpp index 37e879172..0079ec933 100644 --- a/Source/Engine/Particles/ParticleEmitterFunction.cpp +++ b/Source/Engine/Particles/ParticleEmitterFunction.cpp @@ -43,7 +43,6 @@ ParticleEmitterFunction::ParticleEmitterFunction(const SpawnParams& params, cons Asset::LoadResult ParticleEmitterFunction::load() { PROFILE_MEM(Particles); - ScopeWriteLock systemScope(Particles::SystemLocker); // Load graph const auto surfaceChunk = GetChunk(0); @@ -189,7 +188,6 @@ bool ParticleEmitterFunction::SaveSurface(const BytesContainer& data) const { if (OnCheckSave()) return true; - ScopeWriteLock systemScope(Particles::SystemLocker); ScopeLock lock(Locker); // Set Visject Surface data diff --git a/Source/Engine/Particles/Particles.cpp b/Source/Engine/Particles/Particles.cpp index bfbf35f29..951b657b2 100644 --- a/Source/Engine/Particles/Particles.cpp +++ b/Source/Engine/Particles/Particles.cpp @@ -1146,8 +1146,7 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf bounds.Center -= viewOrigin; // Cull particles against all views - uint64 viewsMask = 0; - ASSERT_LOW_LAYER(renderContextBatch.Contexts.Count() <= 64); + bool drawAnyView = false, drawMainView = false; DrawPass viewsDrawModes = DrawPass::None; for (int32 i = 0; i < renderContextBatch.Contexts.Count(); i++) { @@ -1155,11 +1154,12 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf const bool visible = (view.Pass & effect->DrawModes) != DrawPass::None && (view.IsCullingDisabled || view.CullingFrustum.Intersects(bounds)); if (visible) { - viewsMask |= 1ull << (uint64)i; + drawAnyView = true; + drawMainView |= i == 0; viewsDrawModes |= view.Pass; } } - if (viewsMask == 0) + if (drawAnyView == false) return; viewsDrawModes &= effect->DrawModes; @@ -1168,14 +1168,11 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf Matrix worlds[2]; Matrix::Translation(-viewOrigin, worlds[0]); // World renderContextBatch.GetMainContext().View.GetWorldMatrix(effect->GetTransform(), worlds[1]); // Local - float worldDeterminantSigns[2]; - worldDeterminantSigns[0] = Math::FloatSelect(worlds[0].RotDeterminant(), 1, -1); - worldDeterminantSigns[1] = Math::FloatSelect(worlds[1].RotDeterminant(), 1, -1); const StaticFlags staticFlags = effect->GetStaticFlags(); const int8 sortOrder = effect->SortOrder; // Draw lights (only to into the main view) - if ((viewsMask & 1) == 1 && renderContextBatch.GetMainContext().View.Pass != DrawPass::Depth) + if (drawMainView && renderContextBatch.GetMainContext().View.Pass != DrawPass::Depth) { for (int32 emitterIndex = 0; emitterIndex < effect->Instance.Emitters.Count(); emitterIndex++) { @@ -1194,6 +1191,7 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf // Setup a draw call common data DrawCall drawCall; drawCall.PerInstanceRandom = effect->GetPerInstanceRandom(); + drawCall.SetStencilValue(effect->GetLayer()); drawCall.ObjectPosition = bounds.Center; drawCall.ObjectRadius = (float)bounds.Radius; @@ -1209,7 +1207,6 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf continue; drawCall.World = worlds[(int32)emitter->SimulationSpace]; - drawCall.WorldDeterminantSign = worldDeterminantSigns[(int32)emitter->SimulationSpace]; drawCall.Particle.Particles = buffer; // Check if need to render any module @@ -1275,7 +1272,7 @@ void Particles::DrawParticles(RenderContextBatch& renderContextBatch, ParticleEf !material->IsReady() || material->GetInfo().Domain != MaterialDomain::VolumeParticle || (renderContextBatch.GetMainContext().View.Flags & ViewFlags::Fog) == ViewFlags::None || - (viewsMask & 1) == 0 + !drawMainView ) break; renderModulesIndices |= 1u << moduleIndex; diff --git a/Source/Engine/Physics/Actors/IPhysicsDebug.h b/Source/Engine/Physics/Actors/IPhysicsDebug.h index cedd3d822..57e9a97e3 100644 --- a/Source/Engine/Physics/Actors/IPhysicsDebug.h +++ b/Source/Engine/Physics/Actors/IPhysicsDebug.h @@ -12,7 +12,7 @@ public: { } }; -#define ImplementPhysicsDebug void DrawPhysicsDebug(RenderView& view) +#define ImplementPhysicsDebug void DrawPhysicsDebug(RenderView& view) override #else #define ImplementPhysicsDebug #endif diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp index 565bd9fbd..e8fe0b6aa 100644 --- a/Source/Engine/Physics/Actors/RigidBody.cpp +++ b/Source/Engine/Physics/Actors/RigidBody.cpp @@ -159,9 +159,10 @@ void RigidBody::SetCenterOfMassOffset(const Float3& value) { if (value == _centerOfMassOffset) return; + Float3 delta = value - _centerOfMassOffset; _centerOfMassOffset = value; if (_actor) - PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); + PhysicsBackend::AddRigidDynamicActorCenterOfMassOffset(_actor, delta); } void RigidBody::SetConstraints(const RigidbodyConstraints value) @@ -338,6 +339,32 @@ void RigidBody::AddMovement(const Vector3& translation, const Quaternion& rotati SetTransform(t); } +#if USE_EDITOR + +#include "Engine/Debug/DebugDraw.h" + +void RigidBody::OnDebugDrawSelected() +{ + // Draw center of mass + if (!_centerOfMassOffset.IsZero()) + { + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(GetPosition() + (GetOrientation() * (GetCenterOfMass() - GetCenterOfMassOffset())), 5.0f), Color::Red, 0, false); + } + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(GetPosition() + (GetOrientation() * GetCenterOfMass()), 2.5f), Color::Aqua, 0, false); + + // Draw all attached colliders + for (Actor* child : Children) + { + const auto collider = Cast(child); + if (collider && collider->GetAttachedRigidBody() == this) + collider->OnDebugDrawSelf(); + } + + Actor::OnDebugDrawSelected(); +} + +#endif + void RigidBody::OnCollisionEnter(const Collision& c) { CollisionEnter(c); @@ -514,7 +541,7 @@ void RigidBody::BeginPlay(SceneBeginData* data) // Apply the Center Of Mass offset if (!_centerOfMassOffset.IsZero()) - PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); + PhysicsBackend::AddRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); // Register actor PhysicsBackend::AddSceneActor(scene, _actor); diff --git a/Source/Engine/Physics/Actors/RigidBody.h b/Source/Engine/Physics/Actors/RigidBody.h index f9f36edf9..82599ebb8 100644 --- a/Source/Engine/Physics/Actors/RigidBody.h +++ b/Source/Engine/Physics/Actors/RigidBody.h @@ -487,6 +487,9 @@ public: void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; void AddMovement(const Vector3& translation, const Quaternion& rotation) override; +#if USE_EDITOR + void OnDebugDrawSelected() override; +#endif // [IPhysicsActor] void* GetPhysicsActor() const override; diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index a4259a8c8..42da0c7c1 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -201,6 +201,11 @@ void WheeledVehicle::SetSteering(float value) _steering = Math::Clamp(value, -1.0f, 1.0f); } +float WheeledVehicle::GetSteering() +{ + return _steering; +} + void WheeledVehicle::SetBrake(float value) { value = Math::Saturate(value); @@ -209,11 +214,21 @@ void WheeledVehicle::SetBrake(float value) _tankRightBrake = value; } +float WheeledVehicle::GetBrake() +{ + return _brake; +} + void WheeledVehicle::SetHandbrake(float value) { _handBrake = Math::Saturate(value); } +float WheeledVehicle::GetHandbrake() +{ + return _handBrake; +} + void WheeledVehicle::SetTankLeftThrottle(float value) { _tankLeftThrottle = Math::Clamp(value, -1.0f, 1.0f); @@ -387,6 +402,7 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view) void WheeledVehicle::OnDebugDrawSelected() { // Wheels shapes + int32 wheelIndex = 0; for (const auto& wheel : _wheels) { if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger()) @@ -423,14 +439,20 @@ void WheeledVehicle::OnDebugDrawSelected() { DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, false); } + if (ShowDebugDrawWheelNames) + { + const String text = String::Format(TEXT("Index: {}\nCollider: {}"), wheelIndex, wheel.Collider->GetName()); + DEBUG_DRAW_TEXT(text, currentPos, Color::Blue, 10, 0); + } } + wheelIndex++; } // Anti roll bars axes const int32 wheelsCount = _wheels.Count(); - for (int32 i = 0; i < GetAntiRollBars().Count(); i++) + for (int32 i = 0; i < _antiRollBars.Count(); i++) { - const int32 axleIndex = GetAntiRollBars()[i].Axle; + const int32 axleIndex = _antiRollBars[i].Axle; const int32 leftWheelIndex = axleIndex * 2; const int32 rightWheelIndex = leftWheelIndex + 1; if (leftWheelIndex >= wheelsCount || rightWheelIndex >= wheelsCount) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h index 916a9f9ee..3e857ba23 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.h +++ b/Source/Engine/Physics/Actors/WheeledVehicle.h @@ -468,10 +468,18 @@ public: API_FIELD(Attributes="EditorOrder(1), EditorDisplay(\"Vehicle\")") bool UseAnalogSteering = false; +#if USE_EDITOR + /// + /// If checked, will draw wheel names and indices at the position of their colliders. + /// + API_FIELD(Attributes="EditorOrder(2), EditorDisplay(\"Vehicle\")") + bool ShowDebugDrawWheelNames = false; +#endif + /// /// Gets the vehicle driving model type. /// - API_PROPERTY(Attributes="EditorOrder(2), EditorDisplay(\"Vehicle\")") DriveTypes GetDriveType() const; + API_PROPERTY(Attributes="EditorOrder(4), EditorDisplay(\"Vehicle\")") DriveTypes GetDriveType() const; /// /// Sets the vehicle driving model type. @@ -481,12 +489,12 @@ public: /// /// Gets the vehicle wheels settings. /// - API_PROPERTY(Attributes="EditorOrder(4), EditorDisplay(\"Vehicle\")") const Array& GetWheels() const; + API_PROPERTY(Attributes="EditorOrder(5), EditorDisplay(\"Vehicle\")") const Array& GetWheels() const; /// /// Gets the vehicle drive control settings. /// - API_PROPERTY(Attributes="EditorOrder(5), EditorDisplay(\"Vehicle\")") DriveControlSettings GetDriveControl() const; + API_PROPERTY(Attributes="EditorOrder(6), EditorDisplay(\"Vehicle\")") DriveControlSettings GetDriveControl() const; /// /// Sets the vehicle drive control settings. @@ -501,7 +509,7 @@ public: /// /// Gets the vehicle engine settings. /// - API_PROPERTY(Attributes="EditorOrder(6), EditorDisplay(\"Vehicle\")") EngineSettings GetEngine() const; + API_PROPERTY(Attributes="EditorOrder(7), EditorDisplay(\"Vehicle\")") EngineSettings GetEngine() const; /// /// Sets the vehicle engine settings. @@ -511,7 +519,7 @@ public: /// /// Gets the vehicle differential settings. /// - API_PROPERTY(Attributes="EditorOrder(7), EditorDisplay(\"Vehicle\")") DifferentialSettings GetDifferential() const; + API_PROPERTY(Attributes="EditorOrder(8), EditorDisplay(\"Vehicle\")") DifferentialSettings GetDifferential() const; /// /// Sets the vehicle differential settings. @@ -521,7 +529,7 @@ public: /// /// Gets the vehicle gearbox settings. /// - API_PROPERTY(Attributes="EditorOrder(8), EditorDisplay(\"Vehicle\")") GearboxSettings GetGearbox() const; + API_PROPERTY(Attributes="EditorOrder(9), EditorDisplay(\"Vehicle\")") GearboxSettings GetGearbox() const; /// /// Sets the vehicle gearbox settings. @@ -531,7 +539,7 @@ public: // /// Sets axles anti roll bars to increase vehicle stability. /// - API_PROPERTY() void SetAntiRollBars(const Array& value); + API_PROPERTY(Attributes="EditorOrder(10), EditorDisplay(\"Vehicle\")") void SetAntiRollBars(const Array& value); // /// Gets axles anti roll bars. @@ -557,18 +565,36 @@ public: /// The value (-1,1 range). API_FUNCTION() void SetSteering(float value); + /// + /// Gets the vehicle steering. Steer is the analog steer value in range (-1,1) where -1 represents the steering wheel at left lock and +1 represents the steering wheel at right lock. + /// + /// The vehicle steering. + API_FUNCTION() float GetSteering(); + /// /// Sets the input for vehicle brakes. Brake is the analog brake pedal value in range (0,1) where 1 represents the pedal fully pressed and 0 represents the pedal in its rest state. /// /// The value (0,1 range). API_FUNCTION() void SetBrake(float value); + /// + /// Gets the vehicle brakes. Brake is the analog brake pedal value in range (0,1) where 1 represents the pedal fully pressed and 0 represents the pedal in its rest state. + /// + /// The vehicle brake. + API_FUNCTION() float GetBrake(); + /// /// Sets the input for vehicle handbrake. Handbrake is the analog handbrake value in range (0,1) where 1 represents the handbrake fully engaged and 0 represents the handbrake in its rest state. /// /// The value (0,1 range). API_FUNCTION() void SetHandbrake(float value); + /// + /// Gets the vehicle handbrake. Handbrake is the analog handbrake value in range (0,1) where 1 represents the handbrake fully engaged and 0 represents the handbrake in its rest state. + /// + /// The vehicle handbrake. + API_FUNCTION() float GetHandbrake(); + /// /// Sets the input for tank left track throttle. It is the analog accelerator pedal value in range (-1,1) where 1 represents the pedal fully pressed to move to forward, 0 to represents the /// pedal in its rest state and -1 represents the pedal fully pressed to move to backward. The track direction will be inverted if the vehicle current gear is rear. diff --git a/Source/Engine/Physics/Colliders/BoxCollider.cpp b/Source/Engine/Physics/Colliders/BoxCollider.cpp index 160120f87..1e90cb91f 100644 --- a/Source/Engine/Physics/Colliders/BoxCollider.cpp +++ b/Source/Engine/Physics/Colliders/BoxCollider.cpp @@ -86,7 +86,7 @@ void BoxCollider::OnDebugDraw() namespace { - OrientedBoundingBox GetWriteBox(const Vector3& min, const Vector3& max, const float margin) + OrientedBoundingBox GetWireBox(const Vector3& min, const Vector3& max, const float margin) { OrientedBoundingBox box; const Vector3 vec = max - min; @@ -111,11 +111,40 @@ namespace } } -void BoxCollider::OnDebugDrawSelected() +void BoxCollider::OnDebugDrawSelf() { const Color color = Color::GreenYellow; DEBUG_DRAW_WIRE_BOX(_bounds, color * 0.3f, 0, false); + Vector3 corners[8]; + _bounds.GetCorners(corners); + const float margin = Math::Min(1.0f, (float)_bounds.GetSize().MinValue() * 0.01f); + const Color wiresColor = color.AlphaMultiplied(0.6f); + if (margin > 0.05f) + { + DEBUG_DRAW_BOX(GetWireBox(corners[0], corners[1], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[0], corners[3], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[0], corners[4], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[1], corners[2], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[1], corners[5], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[2], corners[3], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[2], corners[6], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[3], corners[7], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[4], corners[5], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[4], corners[7], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[5], corners[6], margin), wiresColor, 0, true); + DEBUG_DRAW_BOX(GetWireBox(corners[6], corners[7], margin), wiresColor, 0, true); + } + else + { + DEBUG_DRAW_WIRE_BOX(_bounds, wiresColor, 0, true); + } +} + +void BoxCollider::OnDebugDrawSelected() +{ + OnDebugDrawSelf(); + if (_contactOffset > 0) { OrientedBoundingBox contactBounds = _bounds; @@ -123,24 +152,6 @@ void BoxCollider::OnDebugDrawSelected() DEBUG_DRAW_WIRE_BOX(contactBounds, Color::Blue.AlphaMultiplied(0.2f), 0, false); } - Vector3 corners[8]; - _bounds.GetCorners(corners); - const float margin = 1.0f; - const Color wiresColor = color.AlphaMultiplied(0.6f); - DEBUG_DRAW_BOX(GetWriteBox(corners[0], corners[1], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[0], corners[3], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[0], corners[4], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[1], corners[2], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[1], corners[5], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[2], corners[3], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[2], corners[6], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[3], corners[7], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[4], corners[5], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[4], corners[7], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[5], corners[6], margin), wiresColor, 0, true); - DEBUG_DRAW_BOX(GetWriteBox(corners[6], corners[7], margin), wiresColor, 0, true); - - // Base Collider::OnDebugDrawSelected(); } diff --git a/Source/Engine/Physics/Colliders/BoxCollider.h b/Source/Engine/Physics/Colliders/BoxCollider.h index c0eeaea5c..7dbbc830d 100644 --- a/Source/Engine/Physics/Colliders/BoxCollider.h +++ b/Source/Engine/Physics/Colliders/BoxCollider.h @@ -52,6 +52,7 @@ public: // [Collider] #if USE_EDITOR void OnDebugDraw() override; + void OnDebugDrawSelf() override; void OnDebugDrawSelected() override; #endif bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp index 8a9e1d1cf..83ce85115 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp @@ -52,6 +52,17 @@ void CapsuleCollider::DrawPhysicsDebug(RenderView& view) DEBUG_DRAW_WIRE_CAPSULE(_transform.LocalToWorld(_center), rotation, radius, height, Color::GreenYellow * 0.8f, 0, true); } +void CapsuleCollider::OnDebugDrawSelf() +{ + Quaternion rotation; + Quaternion::Multiply(_transform.Orientation, Quaternion::Euler(0, 90, 0), rotation); + const float minSize = 0.001f; + const float radius = Math::Max(Math::Abs(_radius) * _cachedScale, minSize); + const float height = Math::Max(Math::Abs(_height) * _cachedScale, minSize); + const Vector3 position = _transform.LocalToWorld(_center); + DEBUG_DRAW_WIRE_CAPSULE(position, rotation, radius, height, Color::GreenYellow, 0, false); +} + void CapsuleCollider::OnDebugDrawSelected() { Quaternion rotation; diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.h b/Source/Engine/Physics/Colliders/CapsuleCollider.h index 234916f87..784d346eb 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.h +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h @@ -56,6 +56,7 @@ public: public: // [Collider] #if USE_EDITOR + void OnDebugDrawSelf() override; void OnDebugDrawSelected() override; #endif bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index 7a5918c49..6980fc4e6 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -244,7 +244,11 @@ void Collider::UpdateGeometry() if (actor) { const auto rigidBody = dynamic_cast(GetParent()); - if (_staticActor != nullptr || (rigidBody && CanAttach(rigidBody))) + if (rigidBody && CanAttach(rigidBody)) + { + Attach(rigidBody); + } + else if (_staticActor != nullptr) { PhysicsBackend::AttachShape(_shape, actor); } diff --git a/Source/Engine/Physics/Colliders/Collider.h b/Source/Engine/Physics/Colliders/Collider.h index edc73b8a3..d05646072 100644 --- a/Source/Engine/Physics/Colliders/Collider.h +++ b/Source/Engine/Physics/Colliders/Collider.h @@ -158,6 +158,12 @@ protected: /// void RemoveStaticActor(); +private: + friend RigidBody; +#if USE_EDITOR + virtual void OnDebugDrawSelf() {} +#endif + public: // [PhysicsColliderActor] RigidBody* GetAttachedRigidBody() const override; diff --git a/Source/Engine/Physics/Colliders/MeshCollider.cpp b/Source/Engine/Physics/Colliders/MeshCollider.cpp index e4e6948e3..91731e7de 100644 --- a/Source/Engine/Physics/Colliders/MeshCollider.cpp +++ b/Source/Engine/Physics/Colliders/MeshCollider.cpp @@ -85,13 +85,18 @@ void MeshCollider::DrawPhysicsDebug(RenderView& view) } } -void MeshCollider::OnDebugDrawSelected() +void MeshCollider::OnDebugDrawSelf() { if (CollisionData && CollisionData->IsLoaded()) { const auto& debugLines = CollisionData->GetDebugLines(); DEBUG_DRAW_LINES(Span(debugLines.Get(), debugLines.Count()), _transform.GetWorld(), Color::GreenYellow, 0, false); } +} + +void MeshCollider::OnDebugDrawSelected() +{ + OnDebugDrawSelf(); // Base Collider::OnDebugDrawSelected(); diff --git a/Source/Engine/Physics/Colliders/MeshCollider.h b/Source/Engine/Physics/Colliders/MeshCollider.h index 44314adff..2e1ce533a 100644 --- a/Source/Engine/Physics/Colliders/MeshCollider.h +++ b/Source/Engine/Physics/Colliders/MeshCollider.h @@ -31,6 +31,7 @@ public: bool CanAttach(RigidBody* rigidBody) const override; bool CanBeTrigger() const override; #if USE_EDITOR + void OnDebugDrawSelf() override; void OnDebugDrawSelected() override; #endif bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; diff --git a/Source/Engine/Physics/Colliders/SphereCollider.cpp b/Source/Engine/Physics/Colliders/SphereCollider.cpp index f40d9e4af..0576ae6cf 100644 --- a/Source/Engine/Physics/Colliders/SphereCollider.cpp +++ b/Source/Engine/Physics/Colliders/SphereCollider.cpp @@ -35,9 +35,14 @@ void SphereCollider::DrawPhysicsDebug(RenderView& view) DEBUG_DRAW_WIRE_SPHERE(_sphere, Color::GreenYellow * 0.8f, 0, true); } -void SphereCollider::OnDebugDrawSelected() +void SphereCollider::OnDebugDrawSelf() { DEBUG_DRAW_WIRE_SPHERE(_sphere, Color::GreenYellow, 0, false); +} + +void SphereCollider::OnDebugDrawSelected() +{ + OnDebugDrawSelf(); if (_contactOffset > 0) { diff --git a/Source/Engine/Physics/Colliders/SphereCollider.h b/Source/Engine/Physics/Colliders/SphereCollider.h index 67addf17b..47459cf34 100644 --- a/Source/Engine/Physics/Colliders/SphereCollider.h +++ b/Source/Engine/Physics/Colliders/SphereCollider.h @@ -36,6 +36,7 @@ public: public: // [Collider] #if USE_EDITOR + void OnDebugDrawSelf() override; void OnDebugDrawSelected() override; #endif bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 5805301ff..8d61e9ba5 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -2518,7 +2518,7 @@ Vector3 PhysicsBackend::GetRigidDynamicActorCenterOfMass(void* actor) return P2C(actorPhysX->getCMassLocalPose().p); } -void PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(void* actor, const Float3& value) +void PhysicsBackend::AddRigidDynamicActorCenterOfMassOffset(void* actor, const Float3& value) { auto actorPhysX = (PxRigidDynamic*)actor; auto pose = actorPhysX->getCMassLocalPose(); diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h index dacd6c7fd..4307d2c6d 100644 --- a/Source/Engine/Physics/PhysicsBackend.h +++ b/Source/Engine/Physics/PhysicsBackend.h @@ -164,7 +164,7 @@ public: static Vector3 GetRigidDynamicActorAngularVelocity(void* actor); static void SetRigidDynamicActorAngularVelocity(void* actor, const Vector3& value, bool wakeUp); static Vector3 GetRigidDynamicActorCenterOfMass(void* actor); - static void SetRigidDynamicActorCenterOfMassOffset(void* actor, const Float3& value); + static void AddRigidDynamicActorCenterOfMassOffset(void* actor, const Float3& value); static bool GetRigidDynamicActorIsSleeping(void* actor); static void RigidDynamicActorSleep(void* actor); static void RigidDynamicActorWakeUp(void* actor); diff --git a/Source/Engine/Platform/Android/AndroidPlatform.cpp b/Source/Engine/Platform/Android/AndroidPlatform.cpp index 18fb85bb9..2f4577877 100644 --- a/Source/Engine/Platform/Android/AndroidPlatform.cpp +++ b/Source/Engine/Platform/Android/AndroidPlatform.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,57 @@ _Unwind_Reason_Code AndroidUnwindCallback(struct _Unwind_Context* context, void* #endif +static void CrashHandler(int32 signal, siginfo_t* info, void* context) +{ + // Skip if engine already crashed + if (Engine::FatalError != FatalErrorType::None) + return; + + // Get exception info + String errorMsg(TEXT("Unhandled exception: ")); + switch (signal) + { +#define CASE(x) case x: errorMsg += TEXT(#x); break + CASE(SIGABRT); + CASE(SIGILL); + CASE(SIGSEGV); + CASE(SIGQUIT); + CASE(SIGFPE); + CASE(SIGBUS); + CASE(SIGSYS); +#undef CASE + default: + errorMsg += StringUtils::ToString(signal); + } + + // Log exception and return to the crash location when using debugger + if (Platform::IsDebuggerPresent()) + { + LOG_STR(Error, errorMsg); + const String stackTrace = Platform::GetStackTrace(3, 60, nullptr); + LOG_STR(Error, stackTrace); + return; + } + + // Crash engine + Platform::Fatal(errorMsg.Get(), nullptr, FatalErrorType::Exception); +} + +void AndroidRegisterCrashHandling() +{ + struct sigaction action; + Platform::MemoryClear(&action, sizeof(action)); + action.sa_sigaction = CrashHandler; + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGILL, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); + sigaction(SIGQUIT, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGBUS, &action, nullptr); + sigaction(SIGSYS, &action, nullptr); +} + struct AndroidKeyEventType { uint32_t KeyCode; @@ -875,6 +927,8 @@ bool AndroidPlatform::Init() DeviceId.D = (uint32)AndroidCpu.ClockSpeed * AndroidCpu.LogicalProcessorCount * AndroidCpu.ProcessorCoreCount * AndroidCpu.CacheLineSize; } + AndroidRegisterCrashHandling(); + // Setup native platform input devices Input::Keyboard = KeyboardImpl = New(); Input::Gamepads.Add(GamepadImpl = New()); diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index 10ae71d7a..d48204fe5 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -258,7 +258,10 @@ bool MacPlatform::Init() // Get device id { - io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); +#if MAC_OS_X_VERSION_MAX_ALLOWED < 120000 +#define kIOMainPortDefault kIOMasterPortDefault +#endif + io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMainPortDefault, "IOService:/"); CFStringRef deviceUuid = (CFStringRef)IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); IOObjectRelease(ioRegistryRoot); String uuidStr = AppleUtils::ToString(deviceUuid); diff --git a/Source/Engine/Platform/Unix/UnixFileSystem.cpp b/Source/Engine/Platform/Unix/UnixFileSystem.cpp index 1fb47f0f5..528df5b88 100644 --- a/Source/Engine/Platform/Unix/UnixFileSystem.cpp +++ b/Source/Engine/Platform/Unix/UnixFileSystem.cpp @@ -2,6 +2,8 @@ #if PLATFORM_UNIX +#define HAS_DIRS !PLATFORM_PS4 && !PLATFORM_PS5 + #include "UnixFileSystem.h" #include "Engine/Platform/File.h" #include "Engine/Core/Types/TimeSpan.h" @@ -13,7 +15,9 @@ #include #include #include +#if HAS_DIRS #include +#endif #if PLATFORM_MAC || PLATFORM_IOS typedef StringAsANSI<> UnixString; @@ -48,6 +52,8 @@ bool UnixFileSystem::CreateDirectory(const StringView& path) return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST; } +#if HAS_DIRS + bool DeleteUnixPathTree(const char* path) { size_t pathLength; @@ -114,8 +120,11 @@ bool DeleteUnixPathTree(const char* path) return false; } +#endif + bool UnixFileSystem::DeleteDirectory(const String& path, bool deleteContents) { +#if HAS_DIRS const UnixString pathANSI(*path, path.Length()); if (deleteContents) { @@ -125,6 +134,9 @@ bool UnixFileSystem::DeleteDirectory(const String& path, bool deleteContents) { return rmdir(pathANSI.Get()) != 0; } +#else + return true; +#endif } bool UnixFileSystem::DirectoryExists(const StringView& path) @@ -151,6 +163,7 @@ bool UnixFileSystem::DirectoryGetFiles(Array& results, const String& pat bool UnixFileSystem::GetChildDirectories(Array& results, const String& path) { +#if HAS_DIRS size_t pathLength; DIR* dir; struct stat statPath, statEntry; @@ -206,6 +219,9 @@ bool UnixFileSystem::GetChildDirectories(Array& results, const String& p closedir(dir); return false; +#else + return true; +#endif } bool UnixFileSystem::FileExists(const StringView& path) @@ -243,12 +259,16 @@ uint64 UnixFileSystem::GetFileSize(const StringView& path) bool UnixFileSystem::IsReadOnly(const StringView& path) { +#if HAS_DIRS const UnixString pathANSI(*path, path.Length()); if (access(pathANSI.Get(), W_OK) == -1) { return errno == EACCES; } return false; +#else + return true; +#endif } bool UnixFileSystem::SetReadOnly(const StringView& path, bool isReadOnly) @@ -299,6 +319,7 @@ bool UnixFileSystem::MoveFile(const StringView& dst, const StringView& src, bool bool UnixFileSystem::getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern) { +#if HAS_DIRS size_t pathLength; struct stat statPath, statEntry; struct dirent* entry; @@ -389,10 +410,14 @@ bool UnixFileSystem::getFilesFromDirectoryTop(Array& results, const char closedir(dir); return false; +#else + return true; +#endif } bool UnixFileSystem::getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern) { +#if HAS_DIRS // Find all files in this directory getFilesFromDirectoryTop(results, path, searchPattern); @@ -452,6 +477,9 @@ bool UnixFileSystem::getFilesFromDirectoryAll(Array& results, const char closedir(dir); return false; +#else + return true; +#endif } DateTime UnixFileSystem::GetFileLastEditTime(const StringView& path) diff --git a/Source/Engine/Render2D/Font.cpp b/Source/Engine/Render2D/Font.cpp index cf478abda..63c59ff70 100644 --- a/Source/Engine/Render2D/Font.cpp +++ b/Source/Engine/Render2D/Font.cpp @@ -388,7 +388,10 @@ int32 Font::HitTestText(const StringView& text, const Float2& location, const Te if (dst < smallestDst) { // Pointer is behind the last character in the line - smallestIndex = line.LastCharIndex + 1; + if (text[line.LastCharIndex] == '\n' && lineIndex != lines.Count() - 1) + smallestIndex = line.LastCharIndex; + else + smallestIndex = line.LastCharIndex + 1; // Fix for last line //if (lineIndex == lines.Count() - 1) diff --git a/Source/Engine/Renderer/DrawCall.h b/Source/Engine/Renderer/DrawCall.h index 1a8d23285..b71b64874 100644 --- a/Source/Engine/Renderer/DrawCall.h +++ b/Source/Engine/Renderer/DrawCall.h @@ -265,16 +265,23 @@ struct DrawCall /// float ObjectRadius; - /// - /// The world matrix determinant sign (used for geometry that is two sided or has inverse scale - needs to flip normal vectors and change triangles culling). - /// - float WorldDeterminantSign; - /// /// The random per-instance value (normalized to range 0-1). /// float PerInstanceRandom; + /// + /// The 8-bit stencil value to write into Depth-Stencil Buffer. + /// + uint8 StencilValue; + + /// + /// The world matrix determinant sign (used for geometry that is two sided or has inverse scale - needs to flip normal vectors and change triangles culling). + /// 0 - sign is positive + /// 1 - sign is negative (flips object surfaces) + /// + uint8 WorldDeterminant : 1; + /// /// The sorting key for the draw call calculate by RenderList. /// @@ -287,6 +294,12 @@ struct DrawCall { Platform::MemoryClear(this, sizeof(DrawCall)); } + + // Packs object layer into the stencil bits. + FORCE_INLINE void SetStencilValue(int32 layer) + { + StencilValue = uint8(layer & 0x1f); + } }; template<> diff --git a/Source/Engine/Renderer/Editor/MaterialComplexity.cpp b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp index 41283f63e..eb4afc26c 100644 --- a/Source/Engine/Renderer/Editor/MaterialComplexity.cpp +++ b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp @@ -129,8 +129,6 @@ void MaterialComplexityMaterialShader::Draw(RenderContext& renderContext, GPUCon DrawCall drawCall; MaterialBase::BindParameters bindParams(context, renderContext, drawCall); bindParams.BindViewData(); - drawCall.WorldDeterminantSign = 1.0f; - drawCall.PerInstanceRandom = 0.0f; context->SetRenderTarget(lightBuffer); for (int32 i = 0; i < decals.Count(); i++) { diff --git a/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp b/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp index c6804f300..f5e264c86 100644 --- a/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp +++ b/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp @@ -50,8 +50,6 @@ void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, context->BindUA(1, overdrawTexture->View()); context->BindUA(2, liveCountTexture->View()); DrawCall drawCall; - drawCall.WorldDeterminantSign = 1.0f; - drawCall.PerInstanceRandom = 0.0f; MaterialBase::BindParameters bindParams(context, renderContext, drawCall); bindParams.BindViewData(); renderContext.View.Pass = DrawPass::QuadOverdraw; @@ -62,11 +60,12 @@ void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, if (boxModel && boxModel->CanBeRendered() && defaultMaterial && defaultMaterial->IsReady()) { // Draw decals - for (int32 i = 0; i < renderContext.List->Decals.Count(); i++) + PROFILE_GPU_CPU_NAMED("Decals"); + for (const RenderDecalData& decal : renderContext.List->Decals) { - const RenderDecalData& decal = renderContext.List->Decals.Get()[i]; drawCall.World = decal.World; defaultMaterial->Bind(bindParams); + bindParams.BindDrawData(); boxModel->Render(context); } } @@ -76,6 +75,7 @@ void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, if (renderContext.List->Sky && skyModel && skyModel->CanBeRendered() && skyMaterial && skyMaterial->IsReady()) { // Draw sky + PROFILE_GPU_CPU_NAMED("Sky"); auto box = skyModel->GetBox(); Matrix m1, m2; Matrix::Scaling(renderContext.View.Far / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1); @@ -83,7 +83,7 @@ void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, m1 *= m2; drawCall.World = m1; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); + bindParams.BindDrawData(); skyMaterial->Bind(bindParams); skyModel->Render(context); } diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 9d3684010..1881aac3b 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -19,6 +19,7 @@ #include "Engine/Content/Content.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Level/Actors/Decal.h" +#include "Engine/Level/Actors/Sky.h" #include "Engine/Engine/Engine.h" GPU_CB_STRUCT(GBufferPassData { @@ -416,8 +417,17 @@ void GBufferPass::DrawSky(RenderContext& renderContext, GPUContext* context) // Calculate sphere model transform to cover far plane Matrix m1, m2; - Matrix::Scaling(renderContext.View.Far / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1); // Scale to fit whole view frustum - Matrix::CreateWorld(renderContext.View.Position, Float3::Up, Float3::Backward, m2); // Rotate sphere model + float size = renderContext.View.Far; + Float3 origin = renderContext.View.Position; + if (dynamic_cast(renderContext.List->Sky)) // TODO: refactor sky rendering (eg. let sky draw with custom projection) + { + BoundingSphere frustumBounds; + renderContext.View.CullingFrustum.GetSphere(frustumBounds); + origin = frustumBounds.Center; + size = frustumBounds.Radius; + } + Matrix::Scaling(size / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1); // Scale to fit whole view frustum + Matrix::CreateWorld(origin, Float3::Up, Float3::Backward, m2); // Rotate sphere model m1 *= m2; // Draw sky @@ -508,6 +518,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light // Draw decal drawCall.World = decal.World; + drawCall.SortKey = (uint64)decal.RenderLayersMask; decal.Material->Bind(bindParams); // TODO: use hardware instancing context->DrawIndexed(drawCall.Draw.IndicesCount); diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index e4ed7d74f..010e14bf9 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -884,7 +884,10 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex for (const auto& e : cascade.Chunks) { if (e.Key.Layer != 0) + { + maxLayer = Math::Max(maxLayer, e.Key.Layer); continue; + } auto& chunk = e.Value; data.ChunkCoord = e.Key.Coord * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE; cascade.NonEmptyChunks.Add(e.Key); diff --git a/Source/Engine/Renderer/ReflectionsPass.cpp b/Source/Engine/Renderer/ReflectionsPass.cpp index d9e8df3fe..5d5f7f432 100644 --- a/Source/Engine/Renderer/ReflectionsPass.cpp +++ b/Source/Engine/Renderer/ReflectionsPass.cpp @@ -25,219 +25,123 @@ GPU_CB_STRUCT(Data { // https://blog.selfshadow.com/publications/s2015-shading-course/ // https://blog.selfshadow.com/publications/s2012-shading-course/ -#include -#include -#include -#define _USE_MATH_DEFINES -#include +#define COMPILE_WITH_ASSETS_IMPORTER 1 +#define COMPILE_WITH_TEXTURE_TOOL 1 +#include "Engine/Engine/Globals.h" +#include "Engine/Core/Math/Math.h" +#include "Engine/Graphics/Textures/TextureData.h" +#include "Engine/ContentImporters/ImportTexture.h" +#include "Engine/ContentImporters/AssetsImportingManager.h" namespace PreIntegratedGF { - static const int Resolution = 128; - static const int NumSamples = 512; + static const int ResolutionX = 128; + static const int ResolutionY = 32; + static const int NumSamples = 256; - struct vec2 { - double x, y; - vec2(double _x, double _y) :x(_x), y(_y) { }; + Float2 Hammersley(int32 i, int32 sampleCount) + { + float E1 = (float)i / (float)sampleCount; + float E2 = (float)((double)ReverseBits((uint32)i) * 2.3283064365386963e-10); + return Float2(E1, E2); + } - vec2& operator /=(const double& b) + Float3 ImportanceSampleGGX(Float2 E, float roughness) + { + float m = roughness * roughness; + float m2 = m * m; + + float phi = 2 * PI * E.X; + float cosTheta = sqrtf((1 - E.Y) / (1 + (m2 - 1) * E.Y)); + float sinTheta = sqrtf(1 - cosTheta * cosTheta); + + return Float3(sinTheta * cosf(phi), sinTheta * sinf(phi), cosTheta); + } + + float Vis_SmithJointApprox(float roughness, float NoV, float NoL) + { + float a = roughness * roughness; + float Vis_SmithV = NoL * (NoV * (1 - a) + a); + float Vis_SmithL = NoV * (NoL * (1 - a) + a); + return 0.5f / (Vis_SmithV + Vis_SmithL); + } + + Float2 IntegrateBRDF(float roughness, float NoV) + { + if (roughness < 0.04f) roughness = 0.04f; + + Float3 V(sqrtf(1 - NoV * NoV), 0, NoV); + float a = 0, b = 0; + for (int32 i = 0; i < NumSamples; i++) { - x /= b; - y /= b; - return *this; - } - }; + Float2 E = Hammersley(i, NumSamples); + Float3 H = ImportanceSampleGGX(E, roughness); + Float3 L = 2 * Float3::Dot(V, H) * H - V; - struct ivec2 { - int x, y; - }; - - struct vec3 { - double x, y, z; - vec3(double _x, double _y, double _z) :x(_x), y(_y), z(_z) { }; - - double dot(const vec3& b) - { - return x*b.x + y*b.y + z*b.z; - } - }; - - vec3 operator*(const double& a, const vec3& b) - { - return vec3(b.x * a, b.y * a, b.z * a); - } - vec3 operator-(const vec3& a, const vec3& b) - { - return vec3(a.x - b.x, a.y - b.y, a.z - b.z); - } - - inline double saturate(double x) - { - if (x < 0) x = 0; - if (x > 1) x = 1; - return x; - } - - unsigned int ReverseBits32(unsigned int bits) - { - bits = (bits << 16) | (bits >> 16); - bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8); - bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4); - bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2); - bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1); - return bits; - } - - inline double rand_0_1() - { - return 1.0 * rand() / RAND_MAX; - } - - inline unsigned int rand_32bit() - { - unsigned int x = rand() & 0xff; - x |= (rand() & 0xff) << 8; - x |= (rand() & 0xff) << 16; - x |= (rand() & 0xff) << 24; - return x; - } - - // using uniform randomness :( - double t1 = rand_0_1(); - unsigned int t2 = rand_32bit(); - vec2 Hammersley(int Index, int NumSamples) - { - double E1 = 1.0 * Index / NumSamples + t1; - E1 = E1 - int(E1); - double E2 = double(ReverseBits32(Index) ^ t2) * 2.3283064365386963e-10; - return vec2(E1, E2); - } - - vec3 ImportanceSampleGGX(vec2 E, double Roughness) - { - double m = Roughness * Roughness; - double m2 = m * m; - - double phi = 2 * PI * E.x; - double cosTheta = sqrt((1 - E.y) / (1 + (m2 - 1) * E.y)); - double sinTheta = sqrt(1 - cosTheta * cosTheta); - - vec3 H(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); - - double d = (cosTheta * m2 - cosTheta) * cosTheta + 1; - double D = m2 / (M_PI*d*d); - double PDF = D * cosTheta; - - return H; - } - - double Vis_SmithJointApprox(double Roughness, double NoV, double NoL) - { - double a = Roughness * Roughness; - double Vis_SmithV = NoL * (NoV * (1 - a) + a); - double Vis_SmithL = NoV * (NoL * (1 - a) + a); - return 0.5 / (Vis_SmithV + Vis_SmithL); - } - - vec2 IntegrateBRDF(double Roughness, double NoV) - { - if (Roughness < 0.04) Roughness = 0.04; - - vec3 V(sqrt(1 - NoV*NoV), 0, NoV); - double A = 0, B = 0; - for (int i = 0; i < NumSamples; i++) - { - vec2 E = Hammersley(i, NumSamples); - vec3 H = ImportanceSampleGGX(E, Roughness); - vec3 L = 2 * V.dot(H) * H - V; - - double NoL = saturate(L.z); - double NoH = saturate(H.z); - double VoH = saturate(V.dot(H)); + float NoL = Math::Saturate(L.Z); + float NoH = Math::Saturate(H.Z); + float VoH = Math::Saturate(Float3::Dot(V, H)); if (NoL > 0) { - double Vis = Vis_SmithJointApprox(Roughness, NoV, NoL); + float Vis = Vis_SmithJointApprox(roughness, NoV, NoL); + float NoL_Vis_PDF = NoL * Vis * (4 * VoH / NoH); - double a = Roughness * Roughness; - double a2 = a*a; - double Vis_SmithV = NoL * sqrt(NoV * (NoV - NoV * a2) + a2); - double Vis_SmithL = NoV * sqrt(NoL * (NoL - NoL * a2) + a2); - - double NoL_Vis_PDF = NoL * Vis * (4 * VoH / NoH); - - double Fc = pow(1 - VoH, 5); - A += (1 - Fc) * NoL_Vis_PDF; - B += Fc * NoL_Vis_PDF; + float Fc = powf(1 - VoH, 5); + a += NoL_Vis_PDF * (1 - Fc); + b += NoL_Vis_PDF * Fc; } } - vec2 res(A, B); - res /= NumSamples; - return res; + return Float2(a, b) / (float)NumSamples; + } + + bool OnGenerate(TextureData& image) + { + // Setup image + image.Width = ResolutionX; + image.Height = ResolutionY; + image.Depth = 1; + image.Format = PixelFormat::R16G16_UNorm; + image.Items.Resize(1); + image.Items[0].Mips.Resize(1); + auto& mip = image.Items[0].Mips[0]; + mip.RowPitch = 4 * image.Width; + mip.DepthPitch = mip.RowPitch * image.Height; + mip.Lines = image.Height; + mip.Data.Allocate(mip.DepthPitch); + + // Generate GF pairs to be sampled in [NoV, roughness] space + auto pos = (uint16*)mip.Data.Get(); + for (int32 y = 0; y < image.Height; y++) + { + float roughness = ((float)y + 0.5f) / (float)image.Height; + for (int32 x = 0; x < image.Width; x++) + { + float NoV = ((float)x + 0.5f) / (float)image.Width; + Float2 brdf = IntegrateBRDF(roughness, NoV); + *pos++ = (uint16)(Math::Saturate(brdf.X) * MAX_uint16 + 0.5f); + *pos++ = (uint16)(Math::Saturate(brdf.Y) * MAX_uint16 + 0.5f); + } + } + + return false; } void Generate() { - String path = Globals::TemporaryFolder / TEXT("PreIntegratedGF.bmp"); - - FILE* pFile = fopen(path.ToSTD().c_str(), "wb"); - - byte data[Resolution * 3 * Resolution]; - int c = 0; - for (int x = 0; x < Resolution; x++) - { - for (int y = 0; y < Resolution; y++) - { - vec2 brdf = IntegrateBRDF(1 - 1.0 * x / (Resolution - 1), 1.0 * y / (Resolution - 1)); - data[c + 2] = byte(brdf.x * 255); - data[c + 1] = byte(brdf.y * 255); - data[c + 0] = 0; - c += 3; - } - } - - BITMAPINFOHEADER BMIH; - BMIH.biSize = sizeof(BITMAPINFOHEADER); - BMIH.biSizeImage = Resolution * Resolution * 3; - BMIH.biSize = sizeof(BITMAPINFOHEADER); - BMIH.biWidth = Resolution; - BMIH.biHeight = Resolution; - BMIH.biPlanes = 1; - BMIH.biBitCount = 24; - BMIH.biCompression = BI_RGB; - BMIH.biSizeImage = Resolution * Resolution * 3; - - BITMAPFILEHEADER bmfh; - int nBitsOffset = sizeof(BITMAPFILEHEADER) + BMIH.biSize; - LONG lImageSize = BMIH.biSizeImage; - LONG lFileSize = nBitsOffset + lImageSize; - - bmfh.bfType = 'B' + ('M' << 8); - bmfh.bfOffBits = nBitsOffset; - bmfh.bfSize = lFileSize; - bmfh.bfReserved1 = bmfh.bfReserved2 = 0; - - //Write the bitmap file header - UINT nWrittenFileHeaderSize = fwrite(&bmfh, 1, sizeof(BITMAPFILEHEADER), pFile); - - //And then the bitmap info header - UINT nWrittenInfoHeaderSize = fwrite(&BMIH, 1, sizeof(BITMAPINFOHEADER), pFile); - - //Finally, write the image data itself - - //-- the data represents our drawing - UINT nWrittenDIBDataSize = fwrite(data, 1, lImageSize, pFile); - - fclose(pFile); - - Guid id; - Importers::TextureImportArgument arg; - arg.Options.Type = FormatType::HdrRGB; - arg.Options.IndependentChannels = true; - arg.Options.IsAtlas = false; - arg.Options.IsSRGB = false; - arg.Options.NeverStream = true; - Content::Import(path, Globals:... + PRE_INTEGRATED_GF_ASSET_NAME, &id, &arg); + Guid id = Guid::Empty; + ImportTexture::Options options; + options.Type = TextureFormatType::HdrRGB; + options.InternalFormat = PixelFormat::R16G16_UNorm; + options.IndependentChannels = true; + options.IsAtlas = false; + options.sRGB = false; + options.NeverStream = true; + options.GenerateMipMaps = false; + options.Compress = false; + options.InternalLoad.Bind(&OnGenerate); + const String path = Globals::EngineContentFolder / PRE_INTEGRATED_GF_ASSET_NAME + ASSET_FILES_EXTENSION_WITH_DOT; + AssetsImportingManager::Create(AssetsImportingManager::CreateTextureTag, path, id, &options); } }; diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index 50bf00f57..bb580aaf3 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -564,7 +564,8 @@ FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& IMaterial::InstancingHandler handler; if (drawCall.Material->CanUseInstancing(handler)) handler.GetHash(drawCall, batchKey); - uint32 drawKey = (uint32)(471 * drawCall.WorldDeterminantSign); + batchKey = (batchKey * 397) ^ drawCall.StencilValue; + uint32 drawKey = (uint32)(471 * drawCall.WorldDeterminant); drawKey = (drawKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[0]); drawKey = (drawKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]); drawKey = (drawKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[2]); @@ -586,8 +587,11 @@ void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawMo ASSERT_LOW_LAYER(drawModes != DrawPass::None && ((uint32)drawModes & ~(uint32)materialDrawModes) == 0); #endif - // Append draw call data + // Finalize draw call initialization + drawCall.WorldDeterminant = drawCall.World.RotDeterminant() < 0 ? 1 : 0; CalculateSortKey(renderContext, drawCall, sortOrder); + + // Append draw call data const int32 index = DrawCalls.Add(drawCall); // Add draw call to proper draw lists @@ -625,8 +629,11 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP #endif const RenderContext& mainRenderContext = renderContextBatch.Contexts.Get()[0]; - // Append draw call data + // Finalize draw call initialization + drawCall.WorldDeterminant = drawCall.World.RotDeterminant() < 0 ? 1 : 0; CalculateSortKey(mainRenderContext, drawCall, sortOrder); + + // Append draw call data const int32 index = DrawCalls.Add(drawCall); // Add draw call to proper draw lists @@ -749,10 +756,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD else { for (int32 i = 0; i < listSize; i++) - { - const DrawCall& drawCall = drawCallsData[listData[i]]; - sortedKeys[i] = drawCall.SortKey; - } + sortedKeys[i] = drawCallsData[listData[i]].SortKey; } // Sort draw calls indices @@ -780,7 +784,8 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD other.InstanceCount != 0 && drawCallHandler.CanBatch == otherHandler.CanBatch && drawCallHandler.CanBatch(drawCall, other, pass) && - drawCall.WorldDeterminantSign * other.WorldDeterminantSign > 0; + drawCall.WorldDeterminant == other.WorldDeterminant && + drawCall.StencilValue == other.StencilValue; if (!canBatch) break; batchSize++; diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 24262162d..7a3ac867a 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -167,6 +167,7 @@ struct RenderDecalData Matrix World; MaterialBase* Material; int32 SortOrder; + uint32 RenderLayersMask; }; /// @@ -651,13 +652,15 @@ GPU_CB_STRUCT(ShaderObjectData FORCE_INLINE void Store(const DrawCall& drawCall) { - Store(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, drawCall.WorldDeterminantSign, drawCall.Surface.LODDitherFactor); + Store(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, drawCall.WorldDeterminant ? -1.0f : 1.0f, drawCall.Surface.LODDitherFactor); } FORCE_INLINE void Load(DrawCall& drawCall) const { - Load(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, drawCall.WorldDeterminantSign, drawCall.Surface.LODDitherFactor); + float worldDeterminantSign; + Load(drawCall.World, drawCall.Surface.PrevWorld, drawCall.Surface.LightmapUVsArea, drawCall.Surface.GeometrySize, drawCall.PerInstanceRandom, worldDeterminantSign, drawCall.Surface.LODDitherFactor); drawCall.ObjectPosition = drawCall.World.GetTranslation(); + drawCall.WorldDeterminant = worldDeterminantSign < 0 ? 1 : 0; } }); diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 4c884cc1b..278c8237d 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -357,8 +357,6 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont const bool isGBufferDebug = GBufferPass::IsDebugView(renderContext.View.Mode); { PROFILE_CPU_NAMED("Setup"); - if (renderContext.View.Origin != renderContext.View.PrevOrigin) - renderContext.Task->CameraCut(); // Cut any temporal effects on rendering origin change const int32 screenWidth = renderContext.Buffers->GetWidth(); const int32 screenHeight = renderContext.Buffers->GetHeight(); setup.UpscaleLocation = renderContext.Task->UpscaleLocation; diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index ea26eb043..e391ef4a9 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -944,7 +944,10 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render Matrix shadowView, shadowProjection, shadowVP, cullingVP; // Create view matrix - Matrix::LookAt(frustumCenter + light.Direction * minExtents.Z, frustumCenter, Float3::Up, shadowView); + Float3 up = Float3::Up; + if (Math::Abs(Float3::Dot(light.Direction, up)) > 0.9f) + up = Float3::Right; + Matrix::LookAt(frustumCenter + light.Direction * minExtents.Z, frustumCenter, up, shadowView); // Create viewport for culling with extended near/far planes due to culling issues (aka pancaking) const float cullRangeExtent = 100000.0f; diff --git a/Source/Engine/Renderer/VolumetricFogPass.cpp b/Source/Engine/Renderer/VolumetricFogPass.cpp index 290c803d2..3928b5d83 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.cpp +++ b/Source/Engine/Renderer/VolumetricFogPass.cpp @@ -167,6 +167,8 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context, (float)_cache.GridSizeZ); auto& fogData = renderContext.Buffers->VolumetricFogData; fogData.MaxDistance = options.Distance; + if (renderContext.Task->IsCameraCut || renderContext.View.IsOriginTeleport()) + _cache.HistoryWeight = 0.0f; // Init data (partial, without directional light or sky light data); GBufferPass::SetInputs(renderContext.View, _cache.Data.GBuffer); @@ -299,7 +301,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext) PROFILE_GPU_CPU("Volumetric Fog"); // TODO: test exponential depth distribution (should give better quality near the camera) - // TODO: use tiled light culling and render unshadowed lights in single pass + // TODO: use tiled light culling and render shadowed/unshadowed lights in single pass // Try to get shadows atlas GPUTexture* shadowMap; @@ -516,7 +518,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext) { PROFILE_GPU("Light Scattering"); - const bool temporalHistoryIsValid = renderContext.Buffers->VolumetricFogHistory && !renderContext.Task->IsCameraCut && Float3::NearEqual(renderContext.Buffers->VolumetricFogHistory->Size3(), cache.GridSize); + const bool temporalHistoryIsValid = renderContext.Buffers->VolumetricFogHistory && Float3::NearEqual(renderContext.Buffers->VolumetricFogHistory->Size3(), cache.GridSize); const auto lightScatteringHistory = temporalHistoryIsValid ? renderContext.Buffers->VolumetricFogHistory : nullptr; context->BindUA(0, lightScattering->ViewVolume()); diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp index fd0596ef5..69fb5aa08 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp @@ -414,8 +414,9 @@ Variant MUtils::UnboxVariant(MObject* value) // Array of Enums for (int32 i = 0; i < array.Count(); i++) { - array[i].SetType(VariantType(VariantType::Enum, elementTypename)); - Platform::MemoryCopy(&array[i].AsUint64, (byte*)ptr + elementSize * i, elementSize); + auto& a = array.Get()[i]; + a.SetType(VariantType(VariantType::Enum, elementTypename)); + Platform::MemoryCopy(&a.AsUint64, (byte*)ptr + elementSize * i, elementSize); } } else if (elementClass->IsValueType()) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 7e717d185..f69e0c060 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -710,7 +710,7 @@ void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, v #if PLATFORM_DESKTOP && !USE_MONO_AOT static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectSetInternalValues")); CallStaticMethod(ScriptingObjectSetInternalValuesPtr, object, unmanagedPtr, id); -#elif !USE_EDITOR +#elif !USE_EDITOR && PLATFORM_SWITCH // TODO: test this on other AOT platforms (Android with Mono JIT doesn't work) static MField* monoUnmanagedPtrField = ::ScriptingObject::GetStaticClass()->GetField("__unmanagedPtr"); static MField* monoIdField = ::ScriptingObject::GetStaticClass()->GetField("__internalId"); if (monoUnmanagedPtrField) @@ -2276,6 +2276,12 @@ bool InitHostfxr() LOG(Info, "Mono runtime version: {0}", String(buildInfo)); mono_free(buildInfo); +#if PLATFORM_ANDROID + // Fix native crashes handling on Android + extern void AndroidRegisterCrashHandling(); + AndroidRegisterCrashHandling(); +#endif + return false; } diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index cc77f2337..2f7b9f9d6 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -916,6 +916,8 @@ ScriptingObject* Scripting::FindObject(Guid id, const MClass* type) if (idsMapping) { idsMapping->TryGet(id, id); + if (!id.IsValid()) + return nullptr; // Skip warning if object was mapped to empty id (intentionally ignored) } // Try to find it diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index eb9afdeae..35bd16eb6 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -249,7 +249,7 @@ ScriptingObject* ScriptingObject::ToNative(MObject* obj) #if USE_CSHARP if (obj) { -#if USE_MONO || USE_MONO_AOT +#if USE_MONO || USE_MONO_AOT || DOTNET_HOST_MONO const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr); CHECK_RETURN(ptrField, nullptr); ptrField->GetValue(obj, &ptr); diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index 466e81d77..77b4ee8a6 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -859,9 +859,7 @@ void Terrain::OnEnable() { auto patch = _patches[i]; if (patch->_physicsActor) - { PhysicsBackend::AddSceneActor(scene, patch->_physicsActor); - } } // Base @@ -880,9 +878,7 @@ void Terrain::OnDisable() { auto patch = _patches[i]; if (patch->_physicsActor) - { PhysicsBackend::RemoveSceneActor(scene, patch->_physicsActor); - } } // Base diff --git a/Source/Engine/Terrain/TerrainChunk.cpp b/Source/Engine/Terrain/TerrainChunk.cpp index 513f6af97..d1bcb7842 100644 --- a/Source/Engine/Terrain/TerrainChunk.cpp +++ b/Source/Engine/Terrain/TerrainChunk.cpp @@ -122,8 +122,8 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const drawCall.Terrain.Lightmap = nullptr; drawCall.Terrain.LightmapUVsArea = Rectangle::Empty; } - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = _perInstanceRandom; + drawCall.SetStencilValue(_patch->_terrain->GetLayer()); #if USE_EDITOR if (renderContext.View.Mode == ViewMode::LightmapUVsDensity) drawCall.Surface.LODDitherFactor = 1.0f; // See LightmapUVsDensityMaterialShader @@ -183,8 +183,8 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi drawCall.Terrain.Lightmap = nullptr; drawCall.Terrain.LightmapUVsArea = Rectangle::Empty; } - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = _perInstanceRandom; + drawCall.SetStencilValue(_patch->_terrain->GetLayer()); #if USE_EDITOR if (renderContext.View.Mode == ViewMode::LightmapUVsDensity) drawCall.Surface.LODDitherFactor = 1.0f; // See LightmapUVsDensityMaterialShader diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index f7896feae..95e9ffd05 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -2230,7 +2230,8 @@ void TerrainPatch::DestroyCollision() void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene(); PhysicsBackend::RemoveCollider(_terrain); - PhysicsBackend::RemoveSceneActor(scene, _physicsActor); + if (_terrain->IsDuringPlay() && _terrain->IsActiveInHierarchy()) + PhysicsBackend::RemoveSceneActor(scene, _physicsActor); PhysicsBackend::DestroyActor(_physicsActor); PhysicsBackend::DestroyShape(_physicsShape); PhysicsBackend::DestroyObject(_physicsHeightField); diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp index cdf5d4b35..4594446ec 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp @@ -106,7 +106,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) Value values[OutputsMax]; for (int32 i = 0; i < OutputsMax; i++) { - const auto outputBox = node->GetBox(Output0BoxID + i); + const auto outputBox = node->TryGetBox(Output0BoxID + i); if (outputBox && outputBox->HasConnection()) { values[i] = writeLocal(VariantType::Float4, node); @@ -119,7 +119,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) for (int32 i = 0; i < InputsMax; i++) { auto inputName = TEXT("Input") + StringUtils::ToString(i); - const auto inputBox = node->GetBox(Input0BoxID + i); + const auto inputBox = node->TryGetBox(Input0BoxID + i); if (inputBox && inputBox->HasConnection()) { auto inputValue = tryGetValue(inputBox, Value::Zero); @@ -131,7 +131,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) for (int32 i = 0; i < OutputsMax; i++) { auto outputName = TEXT("Output") + StringUtils::ToString(i); - const auto outputBox = node->GetBox(Output0BoxID + i); + const auto outputBox = node->TryGetBox(Output0BoxID + i); if (outputBox && outputBox->HasConnection()) { code.Replace(*outputName, *values[i].Value, StringSearchCase::CaseSensitive); @@ -146,7 +146,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) // Link output values to boxes for (int32 i = 0; i < OutputsMax; i++) { - const auto outputBox = node->GetBox(Output0BoxID + i); + const auto outputBox = node->TryGetBox(Output0BoxID + i); if (outputBox && outputBox->HasConnection()) { outputBox->Cache = values[i]; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index 6bd88f2ae..c48a4c569 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -474,6 +474,23 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) value = writeLocal(VariantType::Float3, String::Format(TEXT("GetWorldPos({1}, {0}.rgb)"), depthSample->Value, uv), node); break; } + case MaterialSceneTextures::SceneStencil: + case MaterialSceneTextures::ObjectLayer: + { + auto stencilParam = findOrAddSceneTexture(MaterialSceneTextures::SceneStencil); + const auto parent = box->GetParent>(); + MaterialGraphBox* uvBox = parent->GetBox(0); + bool useCustomUVs = uvBox->HasConnection(); + String uv; + if (useCustomUVs) + uv = MaterialValue::Cast(tryGetValue(uvBox, getUVs), VariantType::Float2).Value; + else + uv = TEXT("input.TexCoord.xy"); + const Char* func = type == MaterialSceneTextures::ObjectLayer ? TEXT("STENCIL_BUFFER_OBJECT_LAYER") : TEXT(""); + value = writeLocal(VariantType::Int, String::Format(TEXT("{2}(STENCIL_BUFFER_LOAD({0}, {1} * ScreenSize.xy))"), stencilParam.ShaderName, uv, func), node); + _includes.Add(TEXT("./Flax/Stencil.hlsl")); + break; + } default: { // Sample single texture diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Tools.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Tools.cpp index 056ddd7ce..3388c965f 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Tools.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Tools.cpp @@ -48,7 +48,7 @@ void MaterialGenerator::ProcessGroupTools(Box* box, Node* node, Value& value) } // Time case 3: - value = box->ID == 1 ? getUnscaledTime : getTime; + value = box->ID == 1 ? getScaledTime : getTime; break; // Panner case 6: diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 9c42d1865..c473f940c 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -5,6 +5,7 @@ #include "MaterialGenerator.h" #include "Engine/Visject/ShaderGraphUtilities.h" #include "Engine/Platform/File.h" +#include "Engine/Platform/FileSystem.h" #include "Engine/Graphics/Materials/MaterialShader.h" #include "Engine/Graphics/Materials/MaterialShaderFeatures.h" #include "Engine/Engine/Globals.h" @@ -47,9 +48,11 @@ enum class FeatureTemplateInputsMapping struct FeatureData { MaterialShaderFeature::GeneratorData Data; + DateTime FileTime; String Inputs[(int32)FeatureTemplateInputsMapping::MAX]; bool Init(); + void CheckReload(); }; namespace @@ -69,6 +72,7 @@ bool FeatureData::Init() LOG(Error, "Cannot open file {0}", path); return true; } + FileTime = FileSystem::GetFileLastEditTime(path); int32 i = 0; const int32 length = contents.Length(); @@ -105,9 +109,23 @@ bool FeatureData::Init() return false; } +void FeatureData::CheckReload() +{ +#if COMPILE_WITH_DEV_ENV + // Reload if template has been modified + const String path = Globals::EngineContentFolder / TEXT("Editor/MaterialTemplates/") + Data.Template; + if (FileTime < FileSystem::GetFileLastEditTime(path)) + { + for (auto& e : Inputs) + e.Clear(); + Init(); + } +#endif +} + MaterialValue MaterialGenerator::getUVs(VariantType::Float2, TEXT("input.TexCoord")); MaterialValue MaterialGenerator::getTime(VariantType::Float, TEXT("TimeParam")); -MaterialValue MaterialGenerator::getUnscaledTime(VariantType::Float, TEXT("UnscaledTimeParam")); +MaterialValue MaterialGenerator::getScaledTime(VariantType::Float, TEXT("ScaledTimeParam")); MaterialValue MaterialGenerator::getNormal(VariantType::Float3, TEXT("input.TBN[2]")); MaterialValue MaterialGenerator::getNormalZero(VariantType::Float3, TEXT("float3(0, 0, 1)")); MaterialValue MaterialGenerator::getVertexColor(VariantType::Float4, TEXT("GetVertexColor(input)")); @@ -183,7 +201,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo type::Generate(feature.Data); \ if (feature.Init()) \ return true; \ - } \ + } else if (COMPILE_WITH_DEV_ENV) Features[typeName].CheckReload(); \ } const bool isOpaque = materialInfo.BlendMode == MaterialBlendMode::Opaque; switch (baseLayer->Domain) @@ -472,7 +490,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo srv = 3; // Objects + Skinning Bones + Prev Bones break; case MaterialDomain::Decal: - srv = 1; // Depth buffer + srv = 2; // Depth buffer + Stencil buffer break; case MaterialDomain::Terrain: srv = 3; // Heightmap + 2 splatmaps diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h index 706929d75..d80e1e359 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h @@ -210,7 +210,7 @@ public: static MaterialValue getUVs; static MaterialValue getTime; - static MaterialValue getUnscaledTime; + static MaterialValue getScaledTime; static MaterialValue getNormal; static MaterialValue getNormalZero; static MaterialValue getVertexColor; diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp index f5b043994..b1340bfa7 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp @@ -528,12 +528,24 @@ bool ImportMaterials(ModelData& result, AssimpImporterData& data, String& errorM aiColor3D aColor; if (aMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, aColor) == AI_SUCCESS) materialSlot.Diffuse.Color = ToColor(aColor); + if (aMaterial->Get(AI_MATKEY_COLOR_EMISSIVE, aColor) == AI_SUCCESS) + materialSlot.Emissive.Color = ToColor(aColor); + if (aMaterial->Get(AI_MATKEY_COLOR_EMISSIVE, aColor) == AI_SUCCESS) + materialSlot.Emissive.Color = ToColor(aColor); bool aBoolean; if (aMaterial->Get(AI_MATKEY_TWOSIDED, aBoolean) == AI_SUCCESS) materialSlot.TwoSided = aBoolean; - bool aFloat; + if (aMaterial->Get(AI_MATKEY_ENABLE_WIREFRAME, aBoolean) == AI_SUCCESS) + materialSlot.Wireframe = aBoolean; + float aFloat; if (aMaterial->Get(AI_MATKEY_OPACITY, aFloat) == AI_SUCCESS) materialSlot.Opacity.Value = aFloat; + if (aMaterial->Get(AI_MATKEY_GLOSSINESS_FACTOR, aFloat) == AI_SUCCESS) + materialSlot.Roughness.Value = 1.0f - aFloat; + else if (aMaterial->Get(AI_MATKEY_SHININESS, aFloat) == AI_SUCCESS) + materialSlot.Roughness.Value = MaterialSlotEntry::ShininessToRoughness(aFloat); + if (aMaterial->Get(AI_MATKEY_EMISSIVE_INTENSITY, aFloat) == AI_SUCCESS) + materialSlot.Emissive.Color *= aFloat; if (EnumHasAnyFlags(data.Options.ImportTypes, ImportDataTypes::Textures)) { @@ -541,6 +553,15 @@ bool ImportMaterials(ModelData& result, AssimpImporterData& data, String& errorM ImportMaterialTexture(result, data, aMaterial, aiTextureType_EMISSIVE, materialSlot.Emissive.TextureIndex, TextureEntry::TypeHint::ColorRGB); ImportMaterialTexture(result, data, aMaterial, aiTextureType_NORMALS, materialSlot.Normals.TextureIndex, TextureEntry::TypeHint::Normals); ImportMaterialTexture(result, data, aMaterial, aiTextureType_OPACITY, materialSlot.Opacity.TextureIndex, TextureEntry::TypeHint::ColorRGBA); + ImportMaterialTexture(result, data, aMaterial, aiTextureType_METALNESS, materialSlot.Metalness.TextureIndex, TextureEntry::TypeHint::ColorRGB); + ImportMaterialTexture(result, data, aMaterial, aiTextureType_DIFFUSE_ROUGHNESS, materialSlot.Roughness.TextureIndex, TextureEntry::TypeHint::ColorRGB); + + if (materialSlot.Roughness.TextureIndex != -1 && (data.Path.EndsWith(TEXT(".gltf")) || data.Path.EndsWith(TEXT(".glb")))) + { + // glTF specification with a single metallicRoughnessTexture (G = roughness, B = metalness) + materialSlot.Roughness.Channel = 1; + materialSlot.Metalness.Channel = 2; + } if (materialSlot.Diffuse.TextureIndex != -1) { diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index cdcd799b3..0ae1e0639 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -1521,6 +1521,9 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option const Char* roughnessNames[] = { TEXT("roughness"), TEXT("rough") }; TrySetupMaterialParameter(materialInstance, ToSpan(roughnessNames, ARRAY_COUNT(roughnessNames)), material.Roughness.Value, MaterialParameterType::Float); TRY_SETUP_TEXTURE_PARAM(Roughness, roughnessNames, Texture); + const Char* metalnessNames[] = { TEXT("metalness"), TEXT("metallic") }; + TrySetupMaterialParameter(materialInstance, ToSpan(metalnessNames, ARRAY_COUNT(metalnessNames)), material.Metalness.Value, MaterialParameterType::Float); + TRY_SETUP_TEXTURE_PARAM(Metalness, metalnessNames, Texture); #undef TRY_SETUP_TEXTURE_PARAM materialInstance->Save(); @@ -1546,11 +1549,22 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID; materialOptions.Roughness.Value = material.Roughness.Value; if (material.Roughness.TextureIndex != -1) + { materialOptions.Roughness.Texture = data.Textures[material.Roughness.TextureIndex].AssetID; + materialOptions.Roughness.Channel = material.Roughness.Channel; + } + materialOptions.Metalness.Value = material.Metalness.Value; + if (material.Metalness.TextureIndex != -1) + { + materialOptions.Metalness.Texture = data.Textures[material.Metalness.TextureIndex].AssetID; + materialOptions.Metalness.Channel = material.Metalness.Channel; + } if (material.Normals.TextureIndex != -1) materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID; if (material.TwoSided || material.Diffuse.HasAlphaMask) materialOptions.Info.CullMode = CullMode::TwoSided; + if (material.Wireframe) + materialOptions.Info.FeaturesFlags |= MaterialFeaturesFlags::Wireframe; if (!Math::IsOne(material.Opacity.Value) || material.Opacity.TextureIndex != -1) materialOptions.Info.BlendMode = MaterialBlendMode::Transparent; AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialTag, assetPath, material.AssetID, &materialOptions); @@ -1612,9 +1626,16 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option // Transform the nodes using the import transformation if (data.LODs.HasItems() && data.LODs[0].Meshes.HasItems()) { + BitArray<> visitedNodes; + visitedNodes.Resize(data.Nodes.Count()); + visitedNodes.SetAll(false); for (int i = 0; i < data.LODs[0].Meshes.Count(); ++i) { auto* meshData = data.LODs[0].Meshes[i]; + int32 nodeIndex = meshData->NodeIndex; + if (visitedNodes[nodeIndex]) + continue; + visitedNodes.Set(nodeIndex, true); Transform transform = importTransform; if (options.UseLocalOrigin) { @@ -1628,8 +1649,6 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option transform.Translation -= center; } - int32 nodeIndex = meshData->NodeIndex; - auto& node = data.Nodes[nodeIndex]; node.LocalTransform = transform.LocalToWorld(node.LocalTransform); } diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h index b09583471..d7545b92e 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.h +++ b/Source/Engine/Tools/ModelTool/ModelTool.h @@ -148,9 +148,11 @@ public: API_ENUM(Attributes="HideInEditor") enum class PositionFormat { // XYZ channels with 32-bit precision (12 bytes per vertex). - Float32, - // XYZ(W) channels with 12-bit precision (8 bytes per vertex). - Float16, + Float32 = 0, + // XYZ(W) channels with 16-bit precision (8 bytes per vertex). + Float16 = 1, + // Selects the most memory-efficient format that can represent positions within a max error defined in project Build Settings. + Automatic = 2, }; /// @@ -159,9 +161,9 @@ public: API_ENUM(Attributes="HideInEditor") enum class TexCoordFormats { // XY channels with 16-bit precision (4 bytes per vertex). - Float16, + Float16 = 0, // XY channels with 8-bit precision (2 bytes per vertex). Valid only for normalized UVs within range [0; 1], scaled or negative UVs won't work. - UNorm8, + UNorm8 = 1, }; /// @@ -226,7 +228,7 @@ public: public: // The imported vertex positions data format to use by meshes. Changing this affects memory usage of the mesh data, performance and overall quality. API_FIELD(Attributes = "EditorOrder(200), EditorDisplay(\"Data Format\"), VisibleIf(nameof(ShowGeometry))") - PositionFormat PositionFormat = PositionFormat::Float32; + PositionFormat PositionFormat = PositionFormat::Automatic; // The imported vertex texture coordinates data format to use by meshes. Changing this affects memory usage of the mesh data, performance and overall quality. API_FIELD(Attributes = "EditorOrder(205), EditorDisplay(\"Data Format\"), VisibleIf(nameof(ShowGeometry))") TexCoordFormats TexCoordFormat = TexCoordFormats::Float16; diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index bf74213d4..d7199a470 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -707,6 +707,8 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path PixelFormat targetFormat = TextureTool::ToPixelFormat(options.Type, width, height, options.Compress); if (options.sRGB) targetFormat = PixelFormatExtensions::TosRGB(targetFormat); + if (options.InternalFormat != PixelFormat::Unknown) + targetFormat = options.InternalFormat; DXGI_FORMAT targetDxgiFormat = ToDxgiFormat(targetFormat); // Check mip levels diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index aa26283ff..97199680c 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -121,6 +121,10 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes="HideInEditor") Array Sprites; + // The custom format to use. Can be used to override default format from texture Type. + API_FIELD(Attributes="HideInEditor") + PixelFormat InternalFormat = PixelFormat::Unknown; + // Function used for fast importing textures used by internal parts of the engine Function InternalLoad; diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index f8f012c15..b88bc4ef3 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -527,6 +527,8 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu PixelFormat targetFormat = ToPixelFormat(options.Type, width, height, options.Compress); if (options.sRGB) targetFormat = PixelFormatExtensions::TosRGB(targetFormat); + if (options.InternalFormat != PixelFormat::Unknown) + targetFormat = options.InternalFormat; // Check mip levels int32 sourceMipLevels = textureDataSrc->GetMipLevels(); diff --git a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs index fa4b5435d..781435740 100644 --- a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for . /// /// - public sealed class GPUTextureBrush : IBrush + public sealed class GPUTextureBrush : IBrush, IEquatable { /// /// The GPU texture. @@ -47,5 +49,29 @@ namespace FlaxEngine.GUI else Render2D.DrawTexture(Texture, rect, color); } + + /// + public bool Equals(GPUTextureBrush other) + { + return other != null && Texture == other.Texture && Filter == other.Filter; + } + + /// + public override bool Equals(object obj) + { + return obj is GPUTextureBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Texture, (int)Filter); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/IBrush.cs b/Source/Engine/UI/GUI/Brushes/IBrush.cs index f11ff6857..861c0b7df 100644 --- a/Source/Engine/UI/GUI/Brushes/IBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/IBrush.cs @@ -1,5 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// @@ -23,7 +25,7 @@ namespace FlaxEngine.GUI /// /// Interface that unifies input source textures, sprites, render targets, and any other brushes to be used in a more generic way. /// - public interface IBrush + public interface IBrush : IComparable { /// /// Gets the size of the image brush in pixels (if relevant). diff --git a/Source/Engine/UI/GUI/Brushes/LinearGradientBrush.cs b/Source/Engine/UI/GUI/Brushes/LinearGradientBrush.cs index 1ece73d1c..d2155a31c 100644 --- a/Source/Engine/UI/GUI/Brushes/LinearGradientBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/LinearGradientBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for linear color gradient (made of 2 color). /// /// - public sealed class LinearGradientBrush : IBrush + public sealed class LinearGradientBrush : IBrush, IEquatable { /// /// The brush start color. @@ -50,5 +52,29 @@ namespace FlaxEngine.GUI var endColor = EndColor * color; Render2D.FillRectangle(rect, startColor, startColor, endColor, endColor); } + + /// + public bool Equals(LinearGradientBrush other) + { + return other != null && StartColor == other.StartColor && EndColor == other.EndColor; + } + + /// + public override bool Equals(object obj) + { + return obj is LinearGradientBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(StartColor, EndColor); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/MaterialBrush.cs b/Source/Engine/UI/GUI/Brushes/MaterialBrush.cs index 13e9dab24..c610e9910 100644 --- a/Source/Engine/UI/GUI/Brushes/MaterialBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/MaterialBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for rendering. /// /// - public sealed class MaterialBrush : IBrush + public sealed class MaterialBrush : IBrush, IEquatable { /// /// The material. @@ -38,5 +40,29 @@ namespace FlaxEngine.GUI { Render2D.DrawMaterial(Material, rect, color); } + + /// + public bool Equals(MaterialBrush other) + { + return other != null && Material == other.Material; + } + + /// + public override bool Equals(object obj) + { + return obj is MaterialBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Material); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/SolidColorBrush.cs b/Source/Engine/UI/GUI/Brushes/SolidColorBrush.cs index 1e4a20670..d848d9368 100644 --- a/Source/Engine/UI/GUI/Brushes/SolidColorBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/SolidColorBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for single color fill. /// /// - public sealed class SolidColorBrush : IBrush + public sealed class SolidColorBrush : IBrush, IEquatable { /// /// The brush color. @@ -39,5 +41,29 @@ namespace FlaxEngine.GUI { Render2D.FillRectangle(rect, Color * color); } + + /// + public bool Equals(SolidColorBrush other) + { + return other != null && Color == other.Color; + } + + /// + public override bool Equals(object obj) + { + return obj is SolidColorBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Color); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs b/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs index 205a9645c..24ca10015 100644 --- a/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/SpriteBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for . /// /// - public sealed class SpriteBrush : IBrush + public sealed class SpriteBrush : IBrush, IEquatable { /// /// The sprite. @@ -47,6 +49,30 @@ namespace FlaxEngine.GUI else Render2D.DrawSprite(Sprite, rect, color); } + + /// + public bool Equals(SpriteBrush other) + { + return other != null && Sprite == other.Sprite && Filter == other.Filter; + } + + /// + public override bool Equals(object obj) + { + return obj is SpriteBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Sprite, (int)Filter); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } /// @@ -121,5 +147,29 @@ namespace FlaxEngine.GUI } #endif } + + /// + public bool Equals(Sprite9SlicingBrush other) + { + return other != null && Sprite == other.Sprite && Filter == other.Filter; + } + + /// + public override bool Equals(object obj) + { + return obj is Sprite9SlicingBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Sprite, (int)Filter); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs index 189e222b9..e3922eebb 100644 --- a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for . /// /// - public sealed class TextureBrush : IBrush + public sealed class TextureBrush : IBrush, IEquatable { /// /// The texture. @@ -47,13 +49,37 @@ namespace FlaxEngine.GUI else Render2D.DrawTexture(Texture, rect, color); } + + /// + public bool Equals(TextureBrush other) + { + return other != null && Texture == other.Texture && Filter == other.Filter; + } + + /// + public override bool Equals(object obj) + { + return obj is TextureBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Texture, (int)Filter); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } /// /// Implementation of for using 9-slicing. /// /// - public sealed class Texture9SlicingBrush : IBrush + public sealed class Texture9SlicingBrush : IBrush, IEquatable { /// /// The texture. @@ -130,5 +156,29 @@ namespace FlaxEngine.GUI } #endif } + + /// + public bool Equals(Texture9SlicingBrush other) + { + return other != null && Texture == other.Texture && Filter == other.Filter && BorderSize == other.BorderSize && Border == other.Border; + } + + /// + public override bool Equals(object obj) + { + return obj is Texture9SlicingBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Texture, (int)Filter, BorderSize, Border.GetHashCode()); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/UIBrush.cs b/Source/Engine/UI/GUI/Brushes/UIBrush.cs index 4441899c0..044c95285 100644 --- a/Source/Engine/UI/GUI/Brushes/UIBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/UIBrush.cs @@ -1,5 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// @@ -20,7 +22,7 @@ namespace FlaxEngine.GUI /// /// /// - public sealed class UIBrush : IBrush + public sealed class UIBrush : IBrush, IEquatable { /// /// The UI Brush asset to use. @@ -71,5 +73,29 @@ namespace FlaxEngine.GUI if (asset != null && asset.Brush != null) asset.Brush.Draw(rect, color); } + + /// + public bool Equals(UIBrush other) + { + return other != null && Asset == other.Asset; + } + + /// + public override bool Equals(object obj) + { + return obj is UIBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Asset); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Brushes/VideoBrush.cs b/Source/Engine/UI/GUI/Brushes/VideoBrush.cs index b8a54662c..25d942ca6 100644 --- a/Source/Engine/UI/GUI/Brushes/VideoBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/VideoBrush.cs @@ -1,12 +1,14 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// /// Implementation of for frame displaying. /// /// - public sealed class VideoBrush : IBrush + public sealed class VideoBrush : IBrush, IEquatable { /// /// The video player to display frame from it. @@ -57,5 +59,29 @@ namespace FlaxEngine.GUI else Render2D.DrawTexture(texture, rect, color); } + + /// + public bool Equals(VideoBrush other) + { + return other != null && Player == other.Player && Filter == other.Filter; + } + + /// + public override bool Equals(object obj) + { + return obj is VideoBrush other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Player, (int)Filter); + } + + /// + public int CompareTo(object obj) + { + return Equals(obj) ? 1 : 0; + } } } diff --git a/Source/Engine/UI/GUI/Common/CheckBox.cs b/Source/Engine/UI/GUI/Common/CheckBox.cs index c779d6e83..47073cb27 100644 --- a/Source/Engine/UI/GUI/Common/CheckBox.cs +++ b/Source/Engine/UI/GUI/Common/CheckBox.cs @@ -181,8 +181,8 @@ namespace FlaxEngine.GUI ImageColor = style.BorderSelected * 1.2f; BorderColor = style.BorderNormal; BorderColorHighlighted = style.BorderSelected; - CheckedImage = new SpriteBrush(style.CheckBoxTick); - IntermediateImage = new SpriteBrush(style.CheckBoxIntermediate); + CheckedImage = style.CheckBoxTick.IsValid ? new SpriteBrush(style.CheckBoxTick) : new SolidColorBrush(style.Foreground); + IntermediateImage = style.CheckBoxIntermediate.IsValid ? new SpriteBrush(style.CheckBoxIntermediate) : new SolidColorBrush(style.ForegroundGrey); CacheBox(); } diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs index 72d4cd188..df77acc14 100644 --- a/Source/Engine/UI/GUI/Common/Label.cs +++ b/Source/Engine/UI/GUI/Common/Label.cs @@ -344,5 +344,11 @@ namespace FlaxEngine.GUI base.PerformLayoutBeforeChildren(); } + + /// + public override string ToString() + { + return $"{GetType()}, '{ConvertedText()}'"; + } } } diff --git a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs index 9a10a327c..20ef1c401 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs @@ -240,11 +240,13 @@ namespace FlaxEngine.GUI // Organize text blocks within line var horizontalAlignments = TextBlockStyle.Alignments.Baseline; + var verticalAlignments = TextBlockStyle.Alignments.Baseline; for (int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++) { ref TextBlock textBlock = ref textBlocks[i]; var vOffset = lineSize.Y - textBlock.Bounds.Height; horizontalAlignments |= textBlock.Style.Alignment & TextBlockStyle.Alignments.HorizontalMask; + verticalAlignments |= textBlock.Style.Alignment & TextBlockStyle.Alignments.VerticalMask; switch (textBlock.Style.Alignment & TextBlockStyle.Alignments.VerticalMask) { case TextBlockStyle.Alignments.Baseline: @@ -272,14 +274,16 @@ namespace FlaxEngine.GUI } } } - var hOffset = Width - lineSize.X; + + // Organize blocks within whole container + var sizeOffset = Size - lineSize; if ((horizontalAlignments & TextBlockStyle.Alignments.Center) == TextBlockStyle.Alignments.Center) { - hOffset *= 0.5f; + sizeOffset.X *= 0.5f; for (int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++) { ref TextBlock textBlock = ref textBlocks[i]; - textBlock.Bounds.Location.X += hOffset; + textBlock.Bounds.Location.X += sizeOffset.X; } } else if ((horizontalAlignments & TextBlockStyle.Alignments.Right) == TextBlockStyle.Alignments.Right) @@ -287,7 +291,24 @@ namespace FlaxEngine.GUI for (int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++) { ref TextBlock textBlock = ref textBlocks[i]; - textBlock.Bounds.Location.X += hOffset; + textBlock.Bounds.Location.X += sizeOffset.X; + } + } + if ((verticalAlignments & TextBlockStyle.Alignments.Middle) == TextBlockStyle.Alignments.Middle) + { + sizeOffset.Y *= 0.5f; + for (int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++) + { + ref TextBlock textBlock = ref textBlocks[i]; + textBlock.Bounds.Location.Y += sizeOffset.Y; + } + } + else if ((verticalAlignments & TextBlockStyle.Alignments.Bottom) == TextBlockStyle.Alignments.Bottom) + { + for (int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++) + { + ref TextBlock textBlock = ref textBlocks[i]; + textBlock.Bounds.Location.Y += sizeOffset.Y; } } diff --git a/Source/Engine/UI/GUI/TextBlockStyle.cs b/Source/Engine/UI/GUI/TextBlockStyle.cs index 399de41a3..fee385dfa 100644 --- a/Source/Engine/UI/GUI/TextBlockStyle.cs +++ b/Source/Engine/UI/GUI/TextBlockStyle.cs @@ -1,5 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; + namespace FlaxEngine.GUI { /// @@ -10,6 +12,7 @@ namespace FlaxEngine.GUI /// /// Text block alignments modes. /// + [Flags] public enum Alignments { /// diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 3a0d03c68..c2f6789c7 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -352,7 +352,7 @@ void TextRender::UpdateLayout() BoundingBox::Transform(_localBox, _transform, _box); BoundingSphere::FromBox(_box, _sphere); if (_sceneRenderingKey != -1) - GetSceneRendering()->UpdateActor(this, _sceneRenderingKey); + GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Auto | ISceneRenderingListener::AutoDelayDuringRendering); } bool TextRender::HasContentLoaded() const @@ -390,8 +390,8 @@ void TextRender::Draw(RenderContext& renderContext) drawCall.ObjectRadius = (float)_sphere.Radius; drawCall.Surface.GeometrySize = _localBox.GetSize(); drawCall.Surface.PrevWorld = _drawState.PrevWorld; - drawCall.WorldDeterminantSign = RenderTools::GetWorldDeterminantSign(drawCall.World); drawCall.PerInstanceRandom = GetPerInstanceRandom(); + drawCall.SetStencilValue(_layer); drawCall.Geometry.IndexBuffer = _ib.GetBuffer(); drawCall.Geometry.VertexBuffers[0] = _vb.GetBuffer(); drawCall.InstanceCount = 1; diff --git a/Source/Engine/Video/Android/VideoBackendAndroid.cpp b/Source/Engine/Video/Android/VideoBackendAndroid.cpp index 3358c46a2..145ce8aab 100644 --- a/Source/Engine/Video/Android/VideoBackendAndroid.cpp +++ b/Source/Engine/Video/Android/VideoBackendAndroid.cpp @@ -353,7 +353,7 @@ bool VideoBackendAndroid::Player_Create(const VideoBackendPlayerInfo& info, Vide { // File (AAsset* or Unix handle) #if VIDEO_API_ANDROID_DEBUG - LOG(Info, "[VideoBackendAndroid] Loading local file"); + LOG(Info, "[VideoBackendAndroid] Loading local file '{}'", info.Url); #endif auto* mediaSource = AMediaDataSource_new(); AMediaDataSource_setUserdata(mediaSource, fileStream); @@ -366,7 +366,7 @@ bool VideoBackendAndroid::Player_Create(const VideoBackendPlayerInfo& info, Vide { // Url #if VIDEO_API_ANDROID_DEBUG - LOG(Info, "[VideoBackendAndroid] Loading url"); + LOG(Info, "[VideoBackendAndroid] Loading url '{}'", info.Url); #endif const StringAsANSI<> url(info.Url.Get(), info.Url.Length()); status = AMediaExtractor_setDataSource(playerAndroid.Extractor, url.Get()); diff --git a/Source/Engine/Visject/ShaderGraph.h b/Source/Engine/Visject/ShaderGraph.h index 84c4b64d0..ab0e7d405 100644 --- a/Source/Engine/Visject/ShaderGraph.h +++ b/Source/Engine/Visject/ShaderGraph.h @@ -14,7 +14,7 @@ #include "Engine/Content/AssetsContainer.h" #include "Engine/Animations/Curve.h" -#define SHADER_GRAPH_MAX_CALL_STACK 100 +#define SHADER_GRAPH_MAX_CALL_STACK 50 enum class MaterialSceneTextures; template diff --git a/Source/Engine/Visject/ShaderGraphUtilities.cpp b/Source/Engine/Visject/ShaderGraphUtilities.cpp index 83db4590a..bdcb55c05 100644 --- a/Source/Engine/Visject/ShaderGraphUtilities.cpp +++ b/Source/Engine/Visject/ShaderGraphUtilities.cpp @@ -157,7 +157,10 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri case MaterialParameterType::GPUTexture: case MaterialParameterType::SceneTexture: case MaterialParameterType::Texture: - format = TEXT("Texture2D {0} : register(t{1});"); + if (param.AsInteger == (int32)MaterialSceneTextures::SceneStencil) + format = TEXT("Texture2D {0} : register(t{1});"); + else + format = TEXT("Texture2D {0} : register(t{1});"); break; case MaterialParameterType::GPUTextureCube: case MaterialParameterType::CubeTexture: diff --git a/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libopenal.a b/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libopenal.a index 5c5eebbb9..6bdec7f7a 100644 --- a/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libopenal.a +++ b/Source/Platforms/Android/Binaries/ThirdParty/ARM64/libopenal.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7179291d2efd8d3c8c8cd494a2c65e5b506e52929b962223f0af9faf2ba09382 -size 20142390 +oid sha256:4743608626b06af2df45dfb3af6b5ca97ecf08fd35d2a7dd14ac9f19d3aadd9e +size 34362142 diff --git a/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.dll b/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.dll index e64bb6cd7..c270e6da5 100644 --- a/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.dll +++ b/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a54bca64e921d32525ed58c52ce802b4ca2c3f8a92c342296da48c55ec1ea58d -size 1112064 +oid sha256:084675cd25a1090424ae7a31a93d69dd52d2752a9940e28104759e9f87c573b4 +size 1407488 diff --git a/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.lib b/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.lib index ae9715a8b..9acd14199 100644 --- a/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.lib +++ b/Source/Platforms/Windows/Binaries/ThirdParty/x64/OpenAL32.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a4ac5af61abb19624dc2ae23bc16af09a062655f3eab89fedf6c0ead6cd935a +oid sha256:b58f1412018cc3618ab579e280bf5fc167479494655dcf440d0239948e44a65d size 37562 diff --git a/Source/Shaders/BRDF.hlsl b/Source/Shaders/BRDF.hlsl index 9eed9a670..37aa36e42 100644 --- a/Source/Shaders/BRDF.hlsl +++ b/Source/Shaders/BRDF.hlsl @@ -58,6 +58,12 @@ float3 F_Schlick(float3 specularColor, float VoH) return saturate(50.0 * specularColor.g) * fc + (1 - fc) * specularColor; } +float3 F_Schlick(float3 f0, float3 f90, float VoH) +{ + float fc = Pow5(1 - VoH); + return f90 * fc + (1 - fc) * f0; +} + #define REFLECTION_CAPTURE_NUM_MIPS 7 #define REFLECTION_CAPTURE_ROUGHEST_MIP 1 #define REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE 1.2 diff --git a/Source/Shaders/ExponentialHeightFog.hlsl b/Source/Shaders/ExponentialHeightFog.hlsl index f6fb918f5..b5af721d8 100644 --- a/Source/Shaders/ExponentialHeightFog.hlsl +++ b/Source/Shaders/ExponentialHeightFog.hlsl @@ -92,4 +92,9 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl return GetExponentialHeightFog(exponentialHeightFog, posWS, camWS, skipDistance, distance(posWS, camWS)); } +float4 CombineVolumetricFog(float4 fog, float4 volumetricFog) +{ + return float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a); +} + #endif diff --git a/Source/Shaders/Fog.shader b/Source/Shaders/Fog.shader index dfea921cc..5c4344688 100644 --- a/Source/Shaders/Fog.shader +++ b/Source/Shaders/Fog.shader @@ -63,7 +63,7 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0 #if VOLUMETRIC_FOG // Sample volumetric fog and mix it in float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0); - fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a); + fog = CombineVolumetricFog(fog, volumetricFog); #endif return fog; diff --git a/Source/Shaders/GBufferCommon.hlsl b/Source/Shaders/GBufferCommon.hlsl index 346c9c24a..678168220 100644 --- a/Source/Shaders/GBufferCommon.hlsl +++ b/Source/Shaders/GBufferCommon.hlsl @@ -27,26 +27,28 @@ bool IsSubsurfaceMode(int shadingModel) return shadingModel == SHADING_MODEL_SUBSURFACE || shadingModel == SHADING_MODEL_FOLIAGE; } -float3 GetDiffuseColor(in float3 color, in float metalness) +float3 GetDiffuseColor(float3 color, float metalness) { - return color - color * metalness; + return color * (1.0 - metalness); } -float3 GetSpecularColor(in float3 color, in float specular, in float metalness) +// [https://google.github.io/filament/Filament.md.html] +float3 GetSpecularColor(float3 color, float specular, float metalness) { - return lerp(0.08 * specular.xxx, color.rgb, metalness.xxx); + float dielectricF0 = 0.16 * specular * specular; + return lerp(dielectricF0.xxx, color, metalness.xxx); } // Calculate material diffuse color -float3 GetDiffuseColor(in GBufferSample gBuffer) +float3 GetDiffuseColor(GBufferSample gBuffer) { - return gBuffer.Color - gBuffer.Color * gBuffer.Metalness; + return GetDiffuseColor(gBuffer.Color, gBuffer.Metalness); } // Calculate material specular color -float3 GetSpecularColor(in GBufferSample gBuffer) +float3 GetSpecularColor(GBufferSample gBuffer) { - return lerp(0.08 * gBuffer.Specular.xxx, gBuffer.Color.rgb, gBuffer.Metalness.xxx); + return GetSpecularColor(gBuffer.Color, gBuffer.Specular, gBuffer.Metalness); } // Compact Normal Storage for Small G-Buffers diff --git a/Source/Shaders/Lighting.hlsl b/Source/Shaders/Lighting.hlsl index 4d6e474fa..2e3f9dc76 100644 --- a/Source/Shaders/Lighting.hlsl +++ b/Source/Shaders/Lighting.hlsl @@ -31,6 +31,7 @@ LightSample StandardShading(GBufferSample gBuffer, float energy, float3 L, float float3 F = F_Schlick(specularColor, VoH); float D = D_GGX(gBuffer.Roughness, NoH) * energy; float Vis = Vis_SmithJointApprox(gBuffer.Roughness, NoV, NoL); + // TODO: apply energy compensation to specular (1.0 + specularColor * (1.0 / PreIntegratedGF.y - 1.0)) lighting.Specular = (D * Vis) * F; #endif lighting.Transmission = 0; diff --git a/Source/Shaders/MaterialCommon.hlsl b/Source/Shaders/MaterialCommon.hlsl index 897b01d7e..02f754c94 100644 --- a/Source/Shaders/MaterialCommon.hlsl +++ b/Source/Shaders/MaterialCommon.hlsl @@ -177,7 +177,7 @@ cbuffer ViewData : register(b1) float3 LargeWorldsChunkIndex; float LargeWorldsChunkSize; float3 ViewPadding0; - float UnscaledTimeParam; + float ScaledTimeParam; }; #endif diff --git a/Source/Shaders/Reflections.shader b/Source/Shaders/Reflections.shader index 1ae38f0eb..dd0b695e5 100644 --- a/Source/Shaders/Reflections.shader +++ b/Source/Shaders/Reflections.shader @@ -78,8 +78,6 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0 // Calculate specular color float3 specularColor = GetSpecularColor(gBuffer); - if (gBuffer.Metalness < 0.001) - specularColor = 0.04f * gBuffer.Specular; // Calculate reflecion color float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos); diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index e13ae9611..3a7f52f7c 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -83,8 +83,6 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0 // Calculate specular color float3 specularColor = GetSpecularColor(gBuffer); - if (gBuffer.Metalness < 0.001) - specularColor = 0.04f * gBuffer.Specular; // Calculate reflection color float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos); diff --git a/Source/Shaders/Sky.shader b/Source/Shaders/Sky.shader index af5d0053c..de29e5d3f 100644 --- a/Source/Shaders/Sky.shader +++ b/Source/Shaders/Sky.shader @@ -7,7 +7,8 @@ #include "./Flax/AtmosphereFog.hlsl" META_CB_BEGIN(0, Data) -float4x4 WVP; +float4x4 WorldViewProjection; +float4x4 InvViewProjection; float3 ViewOffset; float Padding; GBufferData GBuffer; @@ -18,7 +19,7 @@ DECLARE_GBUFFERDATA_ACCESS(GBuffer) struct MaterialInput { - float4 Position : SV_Position; + float4 Position : SV_Position; float4 ScreenPos : TEXCOORD0; }; @@ -30,12 +31,9 @@ MaterialInput VS(ModelInput_PosOnly input) MaterialInput output; // Compute vertex position - output.Position = mul(float4(input.Position.xyz, 1), WVP); + output.Position = mul(float4(input.Position.xyz, 1), WorldViewProjection); output.ScreenPos = output.Position; - // Place pixels on the far plane - output.Position = output.Position.xyzz; - return output; } @@ -45,15 +43,15 @@ GBufferOutput PS_Sky(MaterialInput input) { GBufferOutput output; - // Obtain UVs corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); + // Calculate view vector (unproject at the far plane) + GBufferData gBufferData = GetGBufferData(); + float4 clipPos = float4(input.ScreenPos.xy / input.ScreenPos.w, 1.0, 1.0); + clipPos = mul(clipPos, InvViewProjection); + float3 worldPos = clipPos.xyz / clipPos.w; + float3 viewVector = normalize(worldPos - gBufferData.ViewPos); // Sample atmosphere color - GBufferData gBufferData = GetGBufferData(); - float3 vsPos = GetViewPos(gBufferData, uv, LinearZ2DeviceDepth(gBufferData, 1)); - float3 wsPos = mul(float4(vsPos, 1), gBufferData.InvViewMatrix).xyz; - float3 viewVector = wsPos - gBufferData.ViewPos; - float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, wsPos + ViewOffset, gBufferData.ViewPos + ViewOffset); + float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, gBufferData.ViewPos + ViewOffset, viewVector, gBufferData.ViewFar, float3(0, 0, 0)); // Pack GBuffer output.Light = color; @@ -64,36 +62,3 @@ GBufferOutput PS_Sky(MaterialInput input) return output; } - -META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Fog(Quad_VS2PS input) : SV_Target0 -{ - float4 result; - /* - // Sample GBuffer - GBufferSample gBuffer = SampleGBuffer(GBuffer, input.TexCoord); - - // TODO: set valid scene color for better inscatter reflectance - //float3 sceneColor = gBuffer.Color * AtmosphericFogDensityOffset; - float3 sceneColor = float3(0, 0, 0); - - // Sample atmosphere color - float3 viewVector = gBuffer.WorldPos - GBuffer.ViewPos; - float SceneDepth = length(ViewVector); - result = GetAtmosphericFog(AtmosphericFog, GBuffer.ViewFar, GBuffer.ViewPos, viewVector, SceneDepth, sceneColor); - - //result.rgb = normalize(ViewVector); - //result.rgb = ViewVector; - //result.rgb = SceneDepth.xxx / GBuffer.ViewFar * 0.5f; - - //result = float4(input.TexCoord, 0, 1); - //result = AtmosphereTransmittanceTexture.Sample(SamplerLinearClamp, input.TexCoord); - //result = float4(AtmosphereIrradianceTexture.Sample(SamplerLinearClamp, input.TexCoord).rgb*5.0, 1.0); - //result = AtmosphereInscatterTexture.Sample(SamplerLinearClamp, float3(input.TexCoord.xy, (AtmosphericFogSunDirection.x+1.0)/2.0)); - */ - - // TODO: finish fog - result = float4(1, 0, 0, 1); - - return result; -} diff --git a/Source/Shaders/Stencil.hlsl b/Source/Shaders/Stencil.hlsl new file mode 100644 index 000000000..7cb72f024 --- /dev/null +++ b/Source/Shaders/Stencil.hlsl @@ -0,0 +1,23 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#ifndef __STENCIL__ +#define __STENCIL__ + +#include "./Flax/Common.hlsl" + +// Stencil bits usage (must match RenderBuffers.h) +// [0] | Object Layer +// [1] | Object Layer +// [2] | Object Layer +// [3] | Object Layer +// [4] | Object Layer +// [5] | +// [6] | +// [7] | +#define STENCIL_BUFFER_OBJECT_LAYER(stencil) uint(stencil & 0x1f) +#ifndef STENCIL_BUFFER_SWIZZLE +#define STENCIL_BUFFER_SWIZZLE .g +#endif +#define STENCIL_BUFFER_LOAD(rt, pos) rt.Load(int3(pos, 0)) STENCIL_BUFFER_SWIZZLE + +#endif diff --git a/Source/ThirdParty/OpenAL/al.h b/Source/ThirdParty/OpenAL/al.h index 5071fa5e3..a4e3ad515 100644 --- a/Source/ThirdParty/OpenAL/al.h +++ b/Source/ThirdParty/OpenAL/al.h @@ -1,8 +1,40 @@ #ifndef AL_AL_H #define AL_AL_H +/* NOLINTBEGIN */ #ifdef __cplusplus extern "C" { + +#ifdef _MSVC_LANG +#define AL_CPLUSPLUS _MSVC_LANG +#else +#define AL_CPLUSPLUS __cplusplus +#endif + +#ifndef AL_DISABLE_NOEXCEPT +#if AL_CPLUSPLUS >= 201103L +#define AL_API_NOEXCEPT noexcept +#else +#define AL_API_NOEXCEPT +#endif +#if AL_CPLUSPLUS >= 201703L +#define AL_API_NOEXCEPT17 noexcept +#else +#define AL_API_NOEXCEPT17 +#endif + +#else /* AL_DISABLE_NOEXCEPT */ + +#define AL_API_NOEXCEPT +#define AL_API_NOEXCEPT17 +#endif + +#undef AL_CPLUSPLUS + +#else /* __cplusplus */ + +#define AL_API_NOEXCEPT +#define AL_API_NOEXCEPT17 #endif #ifndef AL_API @@ -455,220 +487,221 @@ typedef void ALvoid; #ifndef AL_NO_PROTOTYPES /* Renderer State management. */ -AL_API void AL_APIENTRY alEnable(ALenum capability); -AL_API void AL_APIENTRY alDisable(ALenum capability); -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability); +AL_API void AL_APIENTRY alEnable(ALenum capability) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDisable(ALenum capability) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) AL_API_NOEXCEPT; /* Context state setting. */ -AL_API void AL_APIENTRY alDopplerFactor(ALfloat value); -AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value); -AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value); -AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel); +AL_API void AL_APIENTRY alDopplerFactor(ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel) AL_API_NOEXCEPT; /* Context state retrieval. */ -AL_API const ALchar* AL_APIENTRY alGetString(ALenum param); -AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values); -AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values); -AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values); -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param); -AL_API ALint AL_APIENTRY alGetInteger(ALenum param); -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param); -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param); +AL_API const ALchar* AL_APIENTRY alGetString(ALenum param) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param) AL_API_NOEXCEPT; +AL_API ALint AL_APIENTRY alGetInteger(ALenum param) AL_API_NOEXCEPT; +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param) AL_API_NOEXCEPT; +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param) AL_API_NOEXCEPT; /** * Obtain the first error generated in the AL context since the last call to * this function. */ -AL_API ALenum AL_APIENTRY alGetError(void); +AL_API ALenum AL_APIENTRY alGetError(void) AL_API_NOEXCEPT; /** Query for the presence of an extension on the AL context. */ -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname); +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname) AL_API_NOEXCEPT; /** * Retrieve the address of a function. The returned function may be context- * specific. */ -AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname); +AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname) AL_API_NOEXCEPT; /** * Retrieve the value of an enum. The returned value may be context-specific. */ -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename); +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename) AL_API_NOEXCEPT; /* Set listener parameters. */ -AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value); -AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value); -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values); +AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) AL_API_NOEXCEPT; /* Get listener parameters. */ -AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values); +AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values) AL_API_NOEXCEPT; /** Create source objects. */ -AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources); +AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) AL_API_NOEXCEPT; /** Delete source objects. */ -AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources); +AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; /** Verify an ID is for a valid source. */ -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source); +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) AL_API_NOEXCEPT; /* Set source parameters. */ -AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value); -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values); +AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) AL_API_NOEXCEPT; /* Get source parameters. */ -AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values); +AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) AL_API_NOEXCEPT; /** Play, restart, or resume a source, setting its state to AL_PLAYING. */ -AL_API void AL_APIENTRY alSourcePlay(ALuint source); +AL_API void AL_APIENTRY alSourcePlay(ALuint source) AL_API_NOEXCEPT; /** Stop a source, setting its state to AL_STOPPED if playing or paused. */ -AL_API void AL_APIENTRY alSourceStop(ALuint source); +AL_API void AL_APIENTRY alSourceStop(ALuint source) AL_API_NOEXCEPT; /** Rewind a source, setting its state to AL_INITIAL. */ -AL_API void AL_APIENTRY alSourceRewind(ALuint source); +AL_API void AL_APIENTRY alSourceRewind(ALuint source) AL_API_NOEXCEPT; /** Pause a source, setting its state to AL_PAUSED if playing. */ -AL_API void AL_APIENTRY alSourcePause(ALuint source); +AL_API void AL_APIENTRY alSourcePause(ALuint source) AL_API_NOEXCEPT; /** Play, restart, or resume a list of sources atomically. */ -AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources); +AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; /** Stop a list of sources atomically. */ -AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources); +AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; /** Rewind a list of sources atomically. */ -AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources); +AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; /** Pause a list of sources atomically. */ -AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources); +AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; /** Queue buffers onto a source */ -AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); +AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers) AL_API_NOEXCEPT; /** Unqueue processed buffers from a source */ -AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); +AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers) AL_API_NOEXCEPT; /** Create buffer objects */ -AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers); +AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) AL_API_NOEXCEPT; /** Delete buffer objects */ -AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers); +AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) AL_API_NOEXCEPT; /** Verify an ID is a valid buffer (including the NULL buffer) */ -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer); +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) AL_API_NOEXCEPT; /** * Copies data into the buffer, interpreting it using the specified format and * samplerate. */ -AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate); +AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate) AL_API_NOEXCEPT; /* Set buffer parameters. */ -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value); -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value); -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values); +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) AL_API_NOEXCEPT; /* Get buffer parameters. */ -AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); -AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value); -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values); +AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) AL_API_NOEXCEPT; #endif /* AL_NO_PROTOTYPES */ /* Pointer-to-function types, useful for storing dynamically loaded AL entry * points. */ -typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability); -typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability); -typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability); -typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param); -typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values); -typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values); -typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param); -typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param); -typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param); -typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param); -typedef ALenum (AL_APIENTRY *LPALGETERROR)(void); -typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname); -typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname); -typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename); -typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources); -typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources); -typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); -typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source); -typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); -typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); -typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers); -typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers); -typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer); -typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate); -typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); -typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); -typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); -typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); -typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); -typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); -typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); -typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); -typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); -typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values); -typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value); -typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value); -typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value); -typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel); +typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability) AL_API_NOEXCEPT17; +typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param) AL_API_NOEXCEPT17; +typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param) AL_API_NOEXCEPT17; +typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param) AL_API_NOEXCEPT17; +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPALGETERROR)(void) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel) AL_API_NOEXCEPT17; #ifdef __cplusplus } /* extern "C" */ #endif +/* NOLINTEND */ #endif /* AL_AL_H */ diff --git a/Source/ThirdParty/OpenAL/alc.h b/Source/ThirdParty/OpenAL/alc.h index 6d2103335..d048ca04d 100644 --- a/Source/ThirdParty/OpenAL/alc.h +++ b/Source/ThirdParty/OpenAL/alc.h @@ -1,8 +1,40 @@ #ifndef AL_ALC_H #define AL_ALC_H +/* NOLINTBEGIN */ #ifdef __cplusplus extern "C" { + +#ifdef _MSVC_LANG +#define ALC_CPLUSPLUS _MSVC_LANG +#else +#define ALC_CPLUSPLUS __cplusplus +#endif + +#ifndef AL_DISABLE_NOEXCEPT +#if ALC_CPLUSPLUS >= 201103L +#define ALC_API_NOEXCEPT noexcept +#else +#define ALC_API_NOEXCEPT +#endif +#if ALC_CPLUSPLUS >= 201703L +#define ALC_API_NOEXCEPT17 noexcept +#else +#define ALC_API_NOEXCEPT17 +#endif + +#else /* AL_DISABLE_NOEXCEPT */ + +#define ALC_API_NOEXCEPT +#define ALC_API_NOEXCEPT17 +#endif + +#undef ALC_CPLUSPLUS + +#else /* __cplusplus */ + +#define ALC_API_NOEXCEPT +#define ALC_API_NOEXCEPT17 #endif #ifndef ALC_API @@ -172,34 +204,34 @@ typedef void ALCvoid; /* Context management. */ /** Create and attach a context to the given device. */ -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist); +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) ALC_API_NOEXCEPT; /** * Makes the given context the active process-wide context. Passing NULL clears * the active context. */ -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context); +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) ALC_API_NOEXCEPT; /** Resumes processing updates for the given context. */ -ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context); +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) ALC_API_NOEXCEPT; /** Suspends updates for the given context. */ -ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context); +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) ALC_API_NOEXCEPT; /** Remove a context from its device and destroys it. */ -ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context); +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API_NOEXCEPT; /** Returns the currently active context. */ -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void); +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) ALC_API_NOEXCEPT; /** Returns the device that a particular context is attached to. */ -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context); +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) ALC_API_NOEXCEPT; /* Device management. */ /** Opens the named playback device. */ -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename); +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) ALC_API_NOEXCEPT; /** Closes the given playback device. */ -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ALC_API_NOEXCEPT; /* Error support. */ /** Obtain the most recent Device error. */ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) ALC_API_NOEXCEPT; /* Extension support. */ @@ -207,24 +239,24 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); * Query for the presence of an extension on the device. Pass a NULL device to * query a device-inspecific extension. */ -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) ALC_API_NOEXCEPT; /** * Retrieve the address of a function. Given a non-NULL device, the returned * function may be device-specific. */ -ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) ALC_API_NOEXCEPT; /** * Retrieve the value of an enum. Given a non-NULL device, the returned value * may be device-specific. */ -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) ALC_API_NOEXCEPT; /* Query functions. */ /** Returns information about the device, and error strings. */ -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) ALC_API_NOEXCEPT; /** Returns information about the device and the version of OpenAL. */ -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) ALC_API_NOEXCEPT; /* Capture functions. */ @@ -232,43 +264,44 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum pa * Opens the named capture device with the given frequency, format, and buffer * size. */ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) ALC_API_NOEXCEPT; /** Closes the given capture device. */ -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device); +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) ALC_API_NOEXCEPT; /** Starts capturing samples into the device buffer. */ -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device); +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) ALC_API_NOEXCEPT; /** Stops capturing samples. Samples in the device buffer remain available. */ -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device); +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) ALC_API_NOEXCEPT; /** Reads samples from the device buffer. */ -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) ALC_API_NOEXCEPT; #endif /* ALC_NO_PROTOTYPES */ /* Pointer-to-function types, useful for storing dynamically loaded ALC entry * points. */ -typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); -typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context); -typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void); -typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context); -typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename); -typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device); -typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device); -typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); -typedef ALCvoid* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); -typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); -typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param); -typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); -typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); -typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); -typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void) ALC_API_NOEXCEPT17; +typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname) ALC_API_NOEXCEPT17; +typedef ALCvoid* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname) ALC_API_NOEXCEPT17; +typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname) ALC_API_NOEXCEPT17; +typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) ALC_API_NOEXCEPT17; +typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) ALC_API_NOEXCEPT17; #ifdef __cplusplus } /* extern "C" */ #endif +/* NOLINTEND */ #endif /* AL_ALC_H */ diff --git a/Source/ThirdParty/OpenAL/alext.h b/Source/ThirdParty/OpenAL/alext.h index d313a999a..3908e1940 100644 --- a/Source/ThirdParty/OpenAL/alext.h +++ b/Source/ThirdParty/OpenAL/alext.h @@ -1,6 +1,7 @@ #ifndef AL_ALEXT_H #define AL_ALEXT_H +/* NOLINTBEGIN */ #include /* Define int64 and uint64 types */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ @@ -25,6 +26,8 @@ typedef uint64_t _alsoft_uint64_t; extern "C" { #endif +struct _GUID; + #ifndef AL_LOKI_IMA_ADPCM_format #define AL_LOKI_IMA_ADPCM_format 1 #define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 @@ -141,9 +144,9 @@ extern "C" { #ifndef AL_EXT_STATIC_BUFFER #define AL_EXT_STATIC_BUFFER 1 -typedef void (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALuint,ALenum,ALvoid*,ALsizei,ALsizei); +typedef void (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALuint,ALenum,ALvoid*,ALsizei,ALsizei) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -void AL_APIENTRY alBufferDataStatic(const ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq); +void AL_APIENTRY alBufferDataStatic(const ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq) AL_API_NOEXCEPT; #endif #endif @@ -159,11 +162,11 @@ void AL_APIENTRY alBufferDataStatic(const ALuint buffer, ALenum format, ALvoid * #ifndef ALC_EXT_thread_local_context #define ALC_EXT_thread_local_context 1 -typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); -typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context) ALC_API_NOEXCEPT17; +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) ALC_API_NOEXCEPT; +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) ALC_API_NOEXCEPT; #endif #endif @@ -176,9 +179,9 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); #define AL_SOFT_buffer_sub_data 1 #define AL_BYTE_RW_OFFSETS_SOFT 0x1031 #define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 -typedef void (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +typedef void (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length) AL_API_NOEXCEPT; #endif #endif @@ -195,12 +198,12 @@ AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const AL #define AL_FOLDBACK_EVENT_STOP 0x4113 #define AL_FOLDBACK_MODE_MONO 0x4101 #define AL_FOLDBACK_MODE_STEREO 0x4102 -typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); -typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); -AL_API void AL_APIENTRY alRequestFoldbackStop(void); +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alRequestFoldbackStop(void) AL_API_NOEXCEPT; #endif #endif @@ -263,15 +266,15 @@ AL_API void AL_APIENTRY alRequestFoldbackStop(void); #define AL_SAMPLE_LENGTH_SOFT 0x200A #define AL_SEC_LENGTH_SOFT 0x200B -typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); -typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format) AL_API_NOEXCEPT; #endif #endif @@ -302,13 +305,13 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #define ALC_6POINT1_SOFT 0x1505 #define ALC_7POINT1_SOFT 0x1506 -typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); -typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); -typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); -ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) AL_API_NOEXCEPT; +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) AL_API_NOEXCEPT; +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) AL_API_NOEXCEPT; #endif #endif @@ -328,31 +331,31 @@ ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffe #define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 typedef _alsoft_int64_t ALint64SOFT; typedef _alsoft_uint64_t ALuint64SOFT; -typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); -typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); -typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); -typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); -typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); -typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); -AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); -AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); -AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) AL_API_NOEXCEPT; #endif #endif @@ -364,11 +367,11 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 #ifndef AL_SOFT_deferred_updates #define AL_SOFT_deferred_updates 1 #define AL_DEFERRED_UPDATES_SOFT 0xC002 -typedef void (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); -typedef void (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +typedef void (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alDeferUpdatesSOFT(void); -AL_API void AL_APIENTRY alProcessUpdatesSOFT(void); +AL_API void AL_APIENTRY alDeferUpdatesSOFT(void) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alProcessUpdatesSOFT(void) AL_API_NOEXCEPT; #endif #endif @@ -400,11 +403,11 @@ AL_API void AL_APIENTRY alProcessUpdatesSOFT(void); #ifndef ALC_SOFT_pause_device #define ALC_SOFT_pause_device 1 -typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); -typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); +typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) ALC_API_NOEXCEPT; +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) ALC_API_NOEXCEPT; #endif #endif @@ -448,11 +451,11 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); #define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 #define ALC_HRTF_SPECIFIER_SOFT 0x1995 #define ALC_HRTF_ID_SOFT 0x1996 -typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); -typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) ALC_API_NOEXCEPT; +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) ALC_API_NOEXCEPT; #endif #endif @@ -467,9 +470,9 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi #define AL_DEFAULT_RESAMPLER_SOFT 0x1211 #define AL_SOURCE_RESAMPLER_SOFT 0x1212 #define AL_RESAMPLER_NAME_SOFT 0x1213 -typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) AL_API_NOEXCEPT; #endif #endif @@ -493,9 +496,9 @@ typedef _alsoft_uint64_t ALCuint64SOFT; #define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 #define AL_SAMPLE_OFFSET_CLOCK_SOFT 0x1202 #define AL_SEC_OFFSET_CLOCK_SOFT 0x1203 -typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values) ALC_API_NOEXCEPT; #endif #endif @@ -552,27 +555,26 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, #define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x19A5 #define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x19A6 typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, - ALsizei length, const ALchar *message, - void *userParam); -typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); -typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); -typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); -typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); + ALsizei length, const ALchar *message, void *userParam) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) AL_API_NOEXCEPT; +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) AL_API_NOEXCEPT; #endif #endif #ifndef ALC_SOFT_reopen_device #define ALC_SOFT_reopen_device typedef ALCboolean (ALC_APIENTRY*LPALCREOPENDEVICESOFT)(ALCdevice *device, - const ALCchar *deviceName, const ALCint *attribs); + const ALCchar *deviceName, const ALCint *attribs) ALC_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, const ALCchar *deviceName, - const ALCint *attribs); + const ALCint *attribs) ALC_API_NOEXCEPT; #endif #endif @@ -580,16 +582,16 @@ ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, const ALCchar *de #define AL_SOFT_callback_buffer #define AL_BUFFER_CALLBACK_FUNCTION_SOFT 0x19A0 #define AL_BUFFER_CALLBACK_USER_PARAM_SOFT 0x19A1 -typedef ALsizei (AL_APIENTRY*ALBUFFERCALLBACKTYPESOFT)(ALvoid *userptr, ALvoid *sampledata, ALsizei numbytes); -typedef void (AL_APIENTRY*LPALBUFFERCALLBACKSOFT)(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr); -typedef void (AL_APIENTRY*LPALGETBUFFERPTRSOFT)(ALuint buffer, ALenum param, ALvoid **value); -typedef void (AL_APIENTRY*LPALGETBUFFER3PTRSOFT)(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3); -typedef void (AL_APIENTRY*LPALGETBUFFERPTRVSOFT)(ALuint buffer, ALenum param, ALvoid **values); +typedef ALsizei (AL_APIENTRY*ALBUFFERCALLBACKTYPESOFT)(ALvoid *userptr, ALvoid *sampledata, ALsizei numbytes) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALBUFFERCALLBACKSOFT)(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETBUFFERPTRSOFT)(ALuint buffer, ALenum param, ALvoid **value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETBUFFER3PTRSOFT)(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETBUFFERPTRVSOFT)(ALuint buffer, ALenum param, ALvoid **values) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr); -AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr); -AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr0, ALvoid **ptr1, ALvoid **ptr2); -AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **ptr); +AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr0, ALvoid **ptr1, ALvoid **ptr2) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **ptr) AL_API_NOEXCEPT; #endif #endif @@ -640,16 +642,451 @@ AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid #ifndef AL_SOFT_source_start_delay #define AL_SOFT_source_start_delay -typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMESOFT)(ALuint source, ALint64SOFT start_time); -typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMEVSOFT)(ALsizei n, const ALuint *sources, ALint64SOFT start_time); +typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMESOFT)(ALuint source, ALint64SOFT start_time) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMEVSOFT)(ALsizei n, const ALuint *sources, ALint64SOFT start_time) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -void AL_APIENTRY alSourcePlayAtTimeSOFT(ALuint source, ALint64SOFT start_time); -void AL_APIENTRY alSourcePlayAtTimevSOFT(ALsizei n, const ALuint *sources, ALint64SOFT start_time); +void AL_APIENTRY alSourcePlayAtTimeSOFT(ALuint source, ALint64SOFT start_time) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePlayAtTimevSOFT(ALsizei n, const ALuint *sources, ALint64SOFT start_time) AL_API_NOEXCEPT; #endif #endif +#ifndef ALC_EXT_debug +#define ALC_EXT_debug +#define ALC_CONTEXT_FLAGS_EXT 0x19CF +#define ALC_CONTEXT_DEBUG_BIT_EXT 0x0001 +#endif + +#ifndef AL_EXT_debug +#define AL_EXT_debug +#define AL_DONT_CARE_EXT 0x0002 +#define AL_DEBUG_OUTPUT_EXT 0x19B2 +#define AL_DEBUG_CALLBACK_FUNCTION_EXT 0x19B3 +#define AL_DEBUG_CALLBACK_USER_PARAM_EXT 0x19B4 +#define AL_DEBUG_SOURCE_API_EXT 0x19B5 +#define AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT 0x19B6 +#define AL_DEBUG_SOURCE_THIRD_PARTY_EXT 0x19B7 +#define AL_DEBUG_SOURCE_APPLICATION_EXT 0x19B8 +#define AL_DEBUG_SOURCE_OTHER_EXT 0x19B9 +#define AL_DEBUG_TYPE_ERROR_EXT 0x19BA +#define AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT 0x19BB +#define AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT 0x19BC +#define AL_DEBUG_TYPE_PORTABILITY_EXT 0x19BD +#define AL_DEBUG_TYPE_PERFORMANCE_EXT 0x19BE +#define AL_DEBUG_TYPE_MARKER_EXT 0x19BF +#define AL_DEBUG_TYPE_PUSH_GROUP_EXT 0x19C0 +#define AL_DEBUG_TYPE_POP_GROUP_EXT 0x19C1 +#define AL_DEBUG_TYPE_OTHER_EXT 0x19C2 +#define AL_DEBUG_SEVERITY_HIGH_EXT 0x19C3 +#define AL_DEBUG_SEVERITY_MEDIUM_EXT 0x19C4 +#define AL_DEBUG_SEVERITY_LOW_EXT 0x19C5 +#define AL_DEBUG_SEVERITY_NOTIFICATION_EXT 0x19C6 +#define AL_DEBUG_LOGGED_MESSAGES_EXT 0x19C7 +#define AL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_EXT 0x19C8 +#define AL_MAX_DEBUG_MESSAGE_LENGTH_EXT 0x19C9 +#define AL_MAX_DEBUG_LOGGED_MESSAGES_EXT 0x19CA +#define AL_MAX_DEBUG_GROUP_STACK_DEPTH_EXT 0x19CB +#define AL_MAX_LABEL_LENGTH_EXT 0x19CC +#define AL_STACK_OVERFLOW_EXT 0x19CD +#define AL_STACK_UNDERFLOW_EXT 0x19CE +#define AL_CONTEXT_FLAGS_EXT 0x19CF +#define AL_BUFFER_EXT 0x1009 /* Same as AL_BUFFER */ +#define AL_SOURCE_EXT 0x19D0 +#define AL_FILTER_EXT 0x19D1 +#define AL_EFFECT_EXT 0x19D2 +#define AL_AUXILIARY_EFFECT_SLOT_EXT 0x19D3 + +typedef void (AL_APIENTRY*ALDEBUGPROCEXT)(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message, void *userParam) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALDEBUGMESSAGECALLBACKEXT)(ALDEBUGPROCEXT callback, void *userParam) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALDEBUGMESSAGEINSERTEXT)(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALDEBUGMESSAGECONTROLEXT)(ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALPUSHDEBUGGROUPEXT)(ALenum source, ALuint id, ALsizei length, const ALchar *message) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALPOPDEBUGGROUPEXT)(void) AL_API_NOEXCEPT17; +typedef ALuint (AL_APIENTRY*LPALGETDEBUGMESSAGELOGEXT)(ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALOBJECTLABELEXT)(ALenum identifier, ALuint name, ALsizei length, const ALchar *label) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETOBJECTLABELEXT)(ALenum identifier, ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY*LPALGETPOINTEREXT)(ALenum pname) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETPOINTERVEXT)(ALenum pname, void **values) AL_API_NOEXCEPT17; +#ifdef AL_ALEXT_PROTOTYPES +void AL_APIENTRY alDebugMessageCallbackEXT(ALDEBUGPROCEXT callback, void *userParam) AL_API_NOEXCEPT; +void AL_APIENTRY alDebugMessageInsertEXT(ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) AL_API_NOEXCEPT; +void AL_APIENTRY alDebugMessageControlEXT(ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) AL_API_NOEXCEPT; +void AL_APIENTRY alPushDebugGroupEXT(ALenum source, ALuint id, ALsizei length, const ALchar *message) AL_API_NOEXCEPT; +void AL_APIENTRY alPopDebugGroupEXT(void) AL_API_NOEXCEPT; +ALuint AL_APIENTRY alGetDebugMessageLogEXT(ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) AL_API_NOEXCEPT; +void AL_APIENTRY alObjectLabelEXT(ALenum identifier, ALuint name, ALsizei length, const ALchar *label) AL_API_NOEXCEPT; +void AL_APIENTRY alGetObjectLabelEXT(ALenum identifier, ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) AL_API_NOEXCEPT; +void* AL_APIENTRY alGetPointerEXT(ALenum pname) AL_API_NOEXCEPT; +void AL_APIENTRY alGetPointervEXT(ALenum pname, void **values) AL_API_NOEXCEPT; +#endif +#endif + +#ifndef ALC_SOFT_system_events +#define ALC_SOFT_system_events +#define ALC_PLAYBACK_DEVICE_SOFT 0x19D4 +#define ALC_CAPTURE_DEVICE_SOFT 0x19D5 +#define ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT 0x19D6 +#define ALC_EVENT_TYPE_DEVICE_ADDED_SOFT 0x19D7 +#define ALC_EVENT_TYPE_DEVICE_REMOVED_SOFT 0x19D8 +#define ALC_EVENT_SUPPORTED_SOFT 0x19D9 +#define ALC_EVENT_NOT_SUPPORTED_SOFT 0x19DA +typedef void (ALC_APIENTRY*ALCEVENTPROCTYPESOFT)(ALCenum eventType, ALCenum deviceType, + ALCdevice *device, ALCsizei length, const ALCchar *message, void *userParam) ALC_API_NOEXCEPT17; +typedef ALCenum (ALC_APIENTRY*LPALCEVENTISSUPPORTEDSOFT)(ALCenum eventType, ALCenum deviceType) ALC_API_NOEXCEPT17; +typedef ALCboolean (ALC_APIENTRY*LPALCEVENTCONTROLSOFT)(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT17; +typedef void (ALC_APIENTRY*LPALCEVENTCALLBACKSOFT)(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT17; +#ifdef AL_ALEXT_PROTOTYPES +ALCenum ALC_APIENTRY alcEventIsSupportedSOFT(ALCenum eventType, ALCenum deviceType) ALC_API_NOEXCEPT; +ALCboolean ALC_APIENTRY alcEventControlSOFT(ALCsizei count, const ALCenum *events, ALCboolean enable) ALC_API_NOEXCEPT; +void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *userParam) ALC_API_NOEXCEPT; +#endif +#endif + +#ifndef AL_EXT_direct_context +#define AL_EXT_direct_context +typedef ALCvoid* (ALC_APIENTRY *LPALCGETPROCADDRESS2)(ALCdevice *device, const ALCchar *funcname) AL_API_NOEXCEPT17; + +typedef void (AL_APIENTRY *LPALENABLEDIRECT)(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDISABLEDIRECT)(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISENABLEDDIRECT)(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDOPPLERFACTORDIRECT)(ALCcontext *context, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSPEEDOFSOUNDDIRECT)(ALCcontext *context, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDISTANCEMODELDIRECT)(ALCcontext *context, ALenum distanceModel) AL_API_NOEXCEPT17; +typedef const ALchar* (AL_APIENTRY *LPALGETSTRINGDIRECT)(ALCcontext *context, ALenum param) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBOOLEANVDIRECT)(ALCcontext *context, ALenum param, ALboolean *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETINTEGERVDIRECT)(ALCcontext *context, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFLOATVDIRECT)(ALCcontext *context, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETDOUBLEVDIRECT)(ALCcontext *context, ALenum param, ALdouble *values) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEANDIRECT)(ALCcontext *context, ALenum param) AL_API_NOEXCEPT17; +typedef ALint (AL_APIENTRY *LPALGETINTEGERDIRECT)(ALCcontext *context, ALenum param) AL_API_NOEXCEPT17; +typedef ALfloat (AL_APIENTRY *LPALGETFLOATDIRECT)(ALCcontext *context, ALenum param) AL_API_NOEXCEPT17; +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLEDIRECT)(ALCcontext *context, ALenum param) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPALGETERRORDIRECT)(ALCcontext *context) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENTDIRECT)(ALCcontext *context, const ALchar *extname) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY *LPALGETPROCADDRESSDIRECT)(ALCcontext *context, const ALchar *fname) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUEDIRECT)(ALCcontext *context, const ALchar *ename) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERFDIRECT)(ALCcontext *context, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENER3FDIRECT)(ALCcontext *context, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERFVDIRECT)(ALCcontext *context, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERIDIRECT)(ALCcontext *context, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENER3IDIRECT)(ALCcontext *context, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALLISTENERIVDIRECT)(ALCcontext *context, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERFDIRECT)(ALCcontext *context, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENER3FDIRECT)(ALCcontext *context, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERFVDIRECT)(ALCcontext *context, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERIDIRECT)(ALCcontext *context, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENER3IDIRECT)(ALCcontext *context, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETLISTENERIVDIRECT)(ALCcontext *context, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENSOURCESDIRECT)(ALCcontext *context, ALsizei n, ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETESOURCESDIRECT)(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISSOURCEDIRECT)(ALCcontext *context, ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEFDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3FDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEFVDIRECT)(ALCcontext *context, ALuint source, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEIDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3IDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEIVDIRECT)(ALCcontext *context, ALuint source, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEFDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3FDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEFVDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEIDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3IDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEIVDIRECT)(ALCcontext *context, ALuint source, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPLAYDIRECT)(ALCcontext *context, ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCESTOPDIRECT)(ALCcontext *context, ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEREWINDDIRECT)(ALCcontext *context, ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPAUSEDIRECT)(ALCcontext *context, ALuint source) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPLAYVDIRECT)(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCESTOPVDIRECT)(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEREWINDVDIRECT)(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPAUSEVDIRECT)(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERSDIRECT)(ALCcontext *context, ALuint source, ALsizei nb, const ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERSDIRECT)(ALCcontext *context, ALuint source, ALsizei nb, ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENBUFFERSDIRECT)(ALCcontext *context, ALsizei n, ALuint *buffers) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEBUFFERSDIRECT)(ALCcontext *context, ALsizei n, const ALuint *buffers) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISBUFFERDIRECT)(ALCcontext *context, ALuint buffer) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERDATADIRECT)(ALCcontext *context, ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERFDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFER3FDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERFVDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERIDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFER3IDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALBUFFERIVDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERFDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFER3FDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERFVDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERIDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFER3IDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERIVDIRECT)(ALCcontext *context, ALuint buffer, ALenum param, ALint *values) AL_API_NOEXCEPT17; +/* ALC_EXT_EFX */ +typedef void (AL_APIENTRY *LPALGENEFFECTSDIRECT)(ALCcontext *context, ALsizei n, ALuint *effects) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEEFFECTSDIRECT)(ALCcontext *context, ALsizei n, const ALuint *effects) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISEFFECTDIRECT)(ALCcontext *context, ALuint effect) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTIDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTIVDIRECT)(ALCcontext *context, ALuint effect, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTFDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTFVDIRECT)(ALCcontext *context, ALuint effect, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTIDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTIVDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTFDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTFVDIRECT)(ALCcontext *context, ALuint effect, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENFILTERSDIRECT)(ALCcontext *context, ALsizei n, ALuint *filters) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEFILTERSDIRECT)(ALCcontext *context, ALsizei n, const ALuint *filters) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISFILTERDIRECT)(ALCcontext *context, ALuint filter) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERIDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERIVDIRECT)(ALCcontext *context, ALuint filter, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERFDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERFVDIRECT)(ALCcontext *context, ALuint filter, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERIDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERIVDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERFDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERFVDIRECT)(ALCcontext *context, ALuint filter, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTSDIRECT)(ALCcontext *context, ALsizei n, ALuint *effectslots) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTSDIRECT)(ALCcontext *context, ALsizei n, const ALuint *effectslots) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOTDIRECT)(ALCcontext *context, ALuint effectslot) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALint value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIVDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, const ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFVDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, const ALfloat *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALint *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIVDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALint *values) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat *value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFVDIRECT)(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat *values) AL_API_NOEXCEPT17; +/* AL_EXT_BUFFER_DATA_STATIC */ +typedef void (AL_APIENTRY *LPALBUFFERDATASTATICDIRECT)(ALCcontext *context, ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq) AL_API_NOEXCEPT17; +/* AL_EXT_debug */ +typedef void (AL_APIENTRY*LPALDEBUGMESSAGECALLBACKDIRECTEXT)(ALCcontext *context, ALDEBUGPROCEXT callback, void *userParam) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALDEBUGMESSAGEINSERTDIRECTEXT)(ALCcontext *context, ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALDEBUGMESSAGECONTROLDIRECTEXT)(ALCcontext *context, ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALPUSHDEBUGGROUPDIRECTEXT)(ALCcontext *context, ALenum source, ALuint id, ALsizei length, const ALchar *message) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALPOPDEBUGGROUPDIRECTEXT)(ALCcontext *context) AL_API_NOEXCEPT17; +typedef ALuint (AL_APIENTRY*LPALGETDEBUGMESSAGELOGDIRECTEXT)(ALCcontext *context, ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALOBJECTLABELDIRECTEXT)(ALCcontext *context, ALenum identifier, ALuint name, ALsizei length, const ALchar *label) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETOBJECTLABELDIRECTEXT)(ALCcontext *context, ALenum identifier, ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY*LPALGETPOINTERDIRECTEXT)(ALCcontext *context, ALenum pname) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY*LPALGETPOINTERVDIRECTEXT)(ALCcontext *context, ALenum pname, void **values) AL_API_NOEXCEPT17; +/* AL_EXT_FOLDBACK */ +typedef void (AL_APIENTRY *LPALREQUESTFOLDBACKSTARTDIRECT)(ALCcontext *context, ALenum mode, ALsizei count, ALsizei length, ALfloat *mem, LPALFOLDBACKCALLBACK callback) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALREQUESTFOLDBACKSTOPDIRECT)(ALCcontext *context) AL_API_NOEXCEPT17; +/* AL_SOFT_buffer_sub_data */ +typedef void (AL_APIENTRY *LPALBUFFERSUBDATADIRECTSOFT)(ALCcontext *context, ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) AL_API_NOEXCEPT17; +/* AL_SOFT_source_latency */ +typedef void (AL_APIENTRY *LPALSOURCEDDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALdouble) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3DDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALdouble,ALdouble,ALdouble) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEDVDIRECTSOFT)(ALCcontext*,ALuint,ALenum,const ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEDDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3DDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEDVDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALdouble*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEI64DIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALint64SOFT) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCE3I64DIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEI64VDIRECTSOFT)(ALCcontext*,ALuint,ALenum,const ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEI64DIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCE3I64DIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETSOURCEI64VDIRECTSOFT)(ALCcontext*,ALuint,ALenum,ALint64SOFT*) AL_API_NOEXCEPT17; +/* AL_SOFT_deferred_updates */ +typedef void (AL_APIENTRY *LPALDEFERUPDATESDIRECTSOFT)(ALCcontext *context) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALPROCESSUPDATESDIRECTSOFT)(ALCcontext *context) AL_API_NOEXCEPT17; +/* AL_SOFT_source_resampler */ +typedef const ALchar* (AL_APIENTRY *LPALGETSTRINGIDIRECTSOFT)(ALCcontext *context, ALenum pname, ALsizei index) AL_API_NOEXCEPT17; +/* AL_SOFT_events */ +typedef void (AL_APIENTRY *LPALEVENTCONTROLDIRECTSOFT)(ALCcontext *context, ALsizei count, const ALenum *types, ALboolean enable) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEVENTCALLBACKDIRECTSOFT)(ALCcontext *context, ALEVENTPROCSOFT callback, void *userParam) AL_API_NOEXCEPT17; +typedef void* (AL_APIENTRY *LPALGETPOINTERDIRECTSOFT)(ALCcontext *context, ALenum pname) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETPOINTERVDIRECTSOFT)(ALCcontext *context, ALenum pname, void **values) AL_API_NOEXCEPT17; +/* AL_SOFT_callback_buffer */ +typedef void (AL_APIENTRY *LPALBUFFERCALLBACKDIRECTSOFT)(ALCcontext *context, ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERPTRDIRECTSOFT)(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **value) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFER3PTRDIRECTSOFT)(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETBUFFERPTRVDIRECTSOFT)(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **values) AL_API_NOEXCEPT17; +/* AL_SOFT_source_start_delay */ +typedef void (AL_APIENTRY *LPALSOURCEPLAYATTIMEDIRECTSOFT)(ALCcontext *context, ALuint source, ALint64SOFT start_time) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALSOURCEPLAYATTIMEVDIRECTSOFT)(ALCcontext *context, ALsizei n, const ALuint *sources, ALint64SOFT start_time) AL_API_NOEXCEPT17; +/* EAX */ +typedef ALenum (AL_APIENTRY *LPEAXSETDIRECT)(ALCcontext *context, const struct _GUID *property_set_id, ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPEAXGETDIRECT)(ALCcontext *context, const struct _GUID *property_set_id, ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPEAXSETBUFFERMODEDIRECT)(ALCcontext *context, ALsizei n, const ALuint *buffers, ALint value) AL_API_NOEXCEPT17; +typedef ALenum (AL_APIENTRY *LPEAXGETBUFFERMODEDIRECT)(ALCcontext *context, ALuint buffer, ALint *pReserved) AL_API_NOEXCEPT17; +#ifdef AL_ALEXT_PROTOTYPES +ALCvoid* ALC_APIENTRY alcGetProcAddress2(ALCdevice *device, const ALCchar *funcName) AL_API_NOEXCEPT; + +void AL_APIENTRY alEnableDirect(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT; +void AL_APIENTRY alDisableDirect(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum capability) AL_API_NOEXCEPT; + +void AL_APIENTRY alDopplerFactorDirect(ALCcontext *context, ALfloat value) AL_API_NOEXCEPT; +void AL_APIENTRY alSpeedOfSoundDirect(ALCcontext *context, ALfloat value) AL_API_NOEXCEPT; +void AL_APIENTRY alDistanceModelDirect(ALCcontext *context, ALenum distanceModel) AL_API_NOEXCEPT; + +const ALchar* AL_APIENTRY alGetStringDirect(ALCcontext *context, ALenum param) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBooleanvDirect(ALCcontext *context, ALenum param, ALboolean *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetIntegervDirect(ALCcontext *context, ALenum param, ALint *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetFloatvDirect(ALCcontext *context, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetDoublevDirect(ALCcontext *context, ALenum param, ALdouble *values) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alGetBooleanDirect(ALCcontext *context, ALenum param) AL_API_NOEXCEPT; +ALint AL_APIENTRY alGetIntegerDirect(ALCcontext *context, ALenum param) AL_API_NOEXCEPT; +ALfloat AL_APIENTRY alGetFloatDirect(ALCcontext *context, ALenum param) AL_API_NOEXCEPT; +ALdouble AL_APIENTRY alGetDoubleDirect(ALCcontext *context, ALenum param) AL_API_NOEXCEPT; + +ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsExtensionPresentDirect(ALCcontext *context, const ALchar *extname) AL_API_NOEXCEPT; +void* AL_APIENTRY alGetProcAddressDirect(ALCcontext *context, const ALchar *fname) AL_API_NOEXCEPT; +ALenum AL_APIENTRY alGetEnumValueDirect(ALCcontext *context, const ALchar *ename) AL_API_NOEXCEPT; + +void AL_APIENTRY alListenerfDirect(ALCcontext *context, ALenum param, ALfloat value) AL_API_NOEXCEPT; +void AL_APIENTRY alListener3fDirect(ALCcontext *context, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +void AL_APIENTRY alListenerfvDirect(ALCcontext *context, ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alListeneriDirect(ALCcontext *context, ALenum param, ALint value) AL_API_NOEXCEPT; +void AL_APIENTRY alListener3iDirect(ALCcontext *context, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +void AL_APIENTRY alListenerivDirect(ALCcontext *context, ALenum param, const ALint *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListenerfDirect(ALCcontext *context, ALenum param, ALfloat *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListener3fDirect(ALCcontext *context, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListenerfvDirect(ALCcontext *context, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListeneriDirect(ALCcontext *context, ALenum param, ALint *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListener3iDirect(ALCcontext *context, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetListenerivDirect(ALCcontext *context, ALenum param, ALint *values) AL_API_NOEXCEPT; + +void AL_APIENTRY alGenSourcesDirect(ALCcontext *context, ALsizei n, ALuint *sources) AL_API_NOEXCEPT; +void AL_APIENTRY alDeleteSourcesDirect(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsSourceDirect(ALCcontext *context, ALuint source) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcefDirect(ALCcontext *context, ALuint source, ALenum param, ALfloat value) AL_API_NOEXCEPT; +void AL_APIENTRY alSource3fDirect(ALCcontext *context, ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcefvDirect(ALCcontext *context, ALuint source, ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceiDirect(ALCcontext *context, ALuint source, ALenum param, ALint value) AL_API_NOEXCEPT; +void AL_APIENTRY alSource3iDirect(ALCcontext *context, ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceivDirect(ALCcontext *context, ALuint source, ALenum param, const ALint *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcefDirect(ALCcontext *context, ALuint source, ALenum param, ALfloat *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSource3fDirect(ALCcontext *context, ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcefvDirect(ALCcontext *context, ALuint source, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourceiDirect(ALCcontext *context, ALuint source, ALenum param, ALint *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSource3iDirect(ALCcontext *context, ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourceivDirect(ALCcontext *context, ALuint source, ALenum param, ALint *values) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePlayDirect(ALCcontext *context, ALuint source) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceStopDirect(ALCcontext *context, ALuint source) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceRewindDirect(ALCcontext *context, ALuint source) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePauseDirect(ALCcontext *context, ALuint source) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePlayvDirect(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceStopvDirect(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceRewindvDirect(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePausevDirect(ALCcontext *context, ALsizei n, const ALuint *sources) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceQueueBuffersDirect(ALCcontext *context, ALuint source, ALsizei nb, const ALuint *buffers) AL_API_NOEXCEPT; +void AL_APIENTRY alSourceUnqueueBuffersDirect(ALCcontext *context, ALuint source, ALsizei nb, ALuint *buffers) AL_API_NOEXCEPT; + +void AL_APIENTRY alGenBuffersDirect(ALCcontext *context, ALsizei n, ALuint *buffers) AL_API_NOEXCEPT; +void AL_APIENTRY alDeleteBuffersDirect(ALCcontext *context, ALsizei n, const ALuint *buffers) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsBufferDirect(ALCcontext *context, ALuint buffer) AL_API_NOEXCEPT; +void AL_APIENTRY alBufferDataDirect(ALCcontext *context, ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate) AL_API_NOEXCEPT; +void AL_APIENTRY alBufferfDirect(ALCcontext *context, ALuint buffer, ALenum param, ALfloat value) AL_API_NOEXCEPT; +void AL_APIENTRY alBuffer3fDirect(ALCcontext *context, ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) AL_API_NOEXCEPT; +void AL_APIENTRY alBufferfvDirect(ALCcontext *context, ALuint buffer, ALenum param, const ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer, ALenum param, ALint value) AL_API_NOEXCEPT; +void AL_APIENTRY alBuffer3iDirect(ALCcontext *context, ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3) AL_API_NOEXCEPT; +void AL_APIENTRY alBufferivDirect(ALCcontext *context, ALuint buffer, ALenum param, const ALint *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferfDirect(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBuffer3fDirect(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferfvDirect(ALCcontext *context, ALuint buffer, ALenum param, ALfloat *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferiDirect(ALCcontext *context, ALuint buffer, ALenum param, ALint *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBuffer3iDirect(ALCcontext *context, ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferivDirect(ALCcontext *context, ALuint buffer, ALenum param, ALint *values) AL_API_NOEXCEPT; + +void AL_APIENTRY alGenEffectsDirect(ALCcontext *context, ALsizei n, ALuint *effects) AL_API_NOEXCEPT; +void AL_APIENTRY alDeleteEffectsDirect(ALCcontext *context, ALsizei n, const ALuint *effects) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsEffectDirect(ALCcontext *context, ALuint effect) AL_API_NOEXCEPT; +void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect, ALenum param, ALint iValue) AL_API_NOEXCEPT; +void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effect, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint effect, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effect, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint effect, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; + +void AL_APIENTRY alGenFiltersDirect(ALCcontext *context, ALsizei n, ALuint *filters) AL_API_NOEXCEPT; +void AL_APIENTRY alDeleteFiltersDirect(ALCcontext *context, ALsizei n, const ALuint *filters) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsFilterDirect(ALCcontext *context, ALuint filter) AL_API_NOEXCEPT; +void AL_APIENTRY alFilteriDirect(ALCcontext *context, ALuint filter, ALenum param, ALint iValue) AL_API_NOEXCEPT; +void AL_APIENTRY alFilterivDirect(ALCcontext *context, ALuint filter, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alFilterfDirect(ALCcontext *context, ALuint filter, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +void AL_APIENTRY alFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetFilteriDirect(ALCcontext *context, ALuint filter, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetFilterivDirect(ALCcontext *context, ALuint filter, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetFilterfDirect(ALCcontext *context, ALuint filter, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetFilterfvDirect(ALCcontext *context, ALuint filter, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; + +void AL_APIENTRY alGenAuxiliaryEffectSlotsDirect(ALCcontext *context, ALsizei n, ALuint *effectslots) AL_API_NOEXCEPT; +void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *context, ALsizei n, const ALuint *effectslots) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY alIsAuxiliaryEffectSlotDirect(ALCcontext *context, ALuint effectslot) AL_API_NOEXCEPT; +void AL_APIENTRY alAuxiliaryEffectSlotiDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALint iValue) AL_API_NOEXCEPT; +void AL_APIENTRY alAuxiliaryEffectSlotivDirect(ALCcontext *context, ALuint effectslot, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alAuxiliaryEffectSlotfDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +void AL_APIENTRY alAuxiliaryEffectSlotfvDirect(ALCcontext *context, ALuint effectslot, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetAuxiliaryEffectSlotiDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetAuxiliaryEffectSlotivDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +void AL_APIENTRY alGetAuxiliaryEffectSlotfDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +void AL_APIENTRY alGetAuxiliaryEffectSlotfvDirect(ALCcontext *context, ALuint effectslot, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; + +void AL_APIENTRY alBufferDataStaticDirect(ALCcontext *context, ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq) AL_API_NOEXCEPT; + +void AL_APIENTRY alDebugMessageCallbackDirectEXT(ALCcontext *context, ALDEBUGPROCEXT callback, void *userParam) AL_API_NOEXCEPT; +void AL_APIENTRY alDebugMessageInsertDirectEXT(ALCcontext *context, ALenum source, ALenum type, ALuint id, ALenum severity, ALsizei length, const ALchar *message) AL_API_NOEXCEPT; +void AL_APIENTRY alDebugMessageControlDirectEXT(ALCcontext *context, ALenum source, ALenum type, ALenum severity, ALsizei count, const ALuint *ids, ALboolean enable) AL_API_NOEXCEPT; +void AL_APIENTRY alPushDebugGroupDirectEXT(ALCcontext *context, ALenum source, ALuint id, ALsizei length, const ALchar *message) AL_API_NOEXCEPT; +void AL_APIENTRY alPopDebugGroupDirectEXT(ALCcontext *context) AL_API_NOEXCEPT; +ALuint AL_APIENTRY alGetDebugMessageLogDirectEXT(ALCcontext *context, ALuint count, ALsizei logBufSize, ALenum *sources, ALenum *types, ALuint *ids, ALenum *severities, ALsizei *lengths, ALchar *logBuf) AL_API_NOEXCEPT; +void AL_APIENTRY alObjectLabelDirectEXT(ALCcontext *context, ALenum identifier, ALuint name, ALsizei length, const ALchar *label) AL_API_NOEXCEPT; +void AL_APIENTRY alGetObjectLabelDirectEXT(ALCcontext *context, ALenum identifier, ALuint name, ALsizei bufSize, ALsizei *length, ALchar *label) AL_API_NOEXCEPT; +void* AL_APIENTRY alGetPointerDirectEXT(ALCcontext *context, ALenum pname) AL_API_NOEXCEPT; +void AL_APIENTRY alGetPointervDirectEXT(ALCcontext *context, ALenum pname, void **values) AL_API_NOEXCEPT; + +void AL_APIENTRY alRequestFoldbackStartDirect(ALCcontext *context, ALenum mode, ALsizei count, ALsizei length, ALfloat *mem, LPALFOLDBACKCALLBACK callback) AL_API_NOEXCEPT; +void AL_APIENTRY alRequestFoldbackStopDirect(ALCcontext *context) AL_API_NOEXCEPT; + +void AL_APIENTRY alBufferSubDataDirectSOFT(ALCcontext *context, ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) AL_API_NOEXCEPT; + +void AL_APIENTRY alSourcedDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALdouble value) AL_API_NOEXCEPT; +void AL_APIENTRY alSource3dDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcedvDirectSOFT(ALCcontext *context, ALuint source, ALenum param, const ALdouble *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcedDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALdouble *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSource3dDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcedvDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALdouble *values) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcei64DirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT value) AL_API_NOEXCEPT; +void AL_APIENTRY alSource3i64DirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcei64vDirectSOFT(ALCcontext *context, ALuint source, ALenum param, const ALint64SOFT *values) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcei64DirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT *value) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSource3i64DirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) AL_API_NOEXCEPT; +void AL_APIENTRY alGetSourcei64vDirectSOFT(ALCcontext *context, ALuint source, ALenum param, ALint64SOFT *values) AL_API_NOEXCEPT; + +void AL_APIENTRY alDeferUpdatesDirectSOFT(ALCcontext *context) AL_API_NOEXCEPT; +void AL_APIENTRY alProcessUpdatesDirectSOFT(ALCcontext *context) AL_API_NOEXCEPT; + +const ALchar* AL_APIENTRY alGetStringiDirectSOFT(ALCcontext *context, ALenum pname, ALsizei index) AL_API_NOEXCEPT; + +void AL_APIENTRY alEventControlDirectSOFT(ALCcontext *context, ALsizei count, const ALenum *types, ALboolean enable) AL_API_NOEXCEPT; +void AL_APIENTRY alEventCallbackDirectSOFT(ALCcontext *context, ALEVENTPROCSOFT callback, void *userParam) AL_API_NOEXCEPT; +void* AL_APIENTRY alGetPointerDirectSOFT(ALCcontext *context, ALenum pname) AL_API_NOEXCEPT; +void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum pname, void **values) AL_API_NOEXCEPT; + +void AL_APIENTRY alBufferCallbackDirectSOFT(ALCcontext *context, ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferPtrDirectSOFT(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **ptr) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBuffer3PtrDirectSOFT(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **ptr0, ALvoid **ptr1, ALvoid **ptr2) AL_API_NOEXCEPT; +void AL_APIENTRY alGetBufferPtrvDirectSOFT(ALCcontext *context, ALuint buffer, ALenum param, ALvoid **ptr) AL_API_NOEXCEPT; + +void AL_APIENTRY alSourcePlayAtTimeDirectSOFT(ALCcontext *context, ALuint source, ALint64SOFT start_time) AL_API_NOEXCEPT; +void AL_APIENTRY alSourcePlayAtTimevDirectSOFT(ALCcontext *context, ALsizei n, const ALuint *sources, ALint64SOFT start_time) AL_API_NOEXCEPT; + +ALenum AL_APIENTRY EAXSetDirect(ALCcontext *context, const struct _GUID *property_set_id, ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) AL_API_NOEXCEPT; +ALenum AL_APIENTRY EAXGetDirect(ALCcontext *context, const struct _GUID *property_set_id, ALuint property_id, ALuint source_id, ALvoid *value, ALuint value_size) AL_API_NOEXCEPT; +ALboolean AL_APIENTRY EAXSetBufferModeDirect(ALCcontext *context, ALsizei n, const ALuint *buffers, ALint value) AL_API_NOEXCEPT; +ALenum AL_APIENTRY EAXGetBufferModeDirect(ALCcontext *context, ALuint buffer, ALint *pReserved) AL_API_NOEXCEPT; +#endif +#endif + +#ifndef AL_SOFT_bformat_hoa +#define AL_SOFT_bformat_hoa +#define AL_UNPACK_AMBISONIC_ORDER_SOFT 0x199D +#endif + #ifdef __cplusplus } #endif +/* NOLINTEND */ #endif diff --git a/Source/ThirdParty/OpenAL/efx-presets.h b/Source/ThirdParty/OpenAL/efx-presets.h index 8539fd517..acd5bf398 100644 --- a/Source/ThirdParty/OpenAL/efx-presets.h +++ b/Source/ThirdParty/OpenAL/efx-presets.h @@ -2,6 +2,7 @@ #ifndef EFX_PRESETS_H #define EFX_PRESETS_H +/* NOLINTBEGIN */ #ifndef EFXEAXREVERBPROPERTIES_DEFINED #define EFXEAXREVERBPROPERTIES_DEFINED @@ -399,4 +400,5 @@ typedef struct { #define EFX_REVERB_PRESET_SMALLWATERROOM \ { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } +/* NOLINTEND */ #endif /* EFX_PRESETS_H */ diff --git a/Source/ThirdParty/OpenAL/efx.h b/Source/ThirdParty/OpenAL/efx.h index 5ab64a64d..1e93bf222 100644 --- a/Source/ThirdParty/OpenAL/efx.h +++ b/Source/ThirdParty/OpenAL/efx.h @@ -1,6 +1,7 @@ #ifndef AL_EFX_H #define AL_EFX_H +/* NOLINTBEGIN */ #include #include "alc.h" @@ -204,80 +205,80 @@ extern "C" { /* Effect object function types. */ -typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); -typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; /* Filter object function types. */ -typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); -typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; /* Auxiliary Effect Slot object function types. */ -typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); -typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); -typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); -typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); -typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*) AL_API_NOEXCEPT17; +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*) AL_API_NOEXCEPT17; #ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); -AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); -AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); -AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); -AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); -AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); -AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); -AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); -AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); -AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); +AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; -AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); -AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); -AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); -AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); -AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); -AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); -AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); -AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); -AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); -AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); +AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; -AL_API void AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); -AL_API void AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); -AL_API void AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); -AL_API void AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); -AL_API void AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); -AL_API void AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); -AL_API void AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); -AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +AL_API void AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) AL_API_NOEXCEPT; +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue) AL_API_NOEXCEPT; +AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues) AL_API_NOEXCEPT; #endif /* Filter ranges and defaults. */ @@ -758,5 +759,6 @@ AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum par #ifdef __cplusplus } /* extern "C" */ #endif +/* NOLINTEND */ #endif /* AL_EFX_H */ diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs index 97f0d80bd..bac529778 100644 --- a/Source/ThirdParty/nethost/nethost.Build.cs +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -112,6 +112,7 @@ public class nethost : ThirdPartyModule { // Use CoreCLR for runtime hosting options.PublicDefinitions.Add("DOTNET_HOST_CORECLR"); + options.ScriptingAPI.Defines.Add("DOTNET_HOST_CORECLR"); options.PublicIncludePaths.Add(hostRuntime.Path); break; } @@ -119,6 +120,7 @@ public class nethost : ThirdPartyModule { // Use Mono for runtime hosting options.PublicDefinitions.Add("DOTNET_HOST_MONO"); + options.ScriptingAPI.Defines.Add("DOTNET_HOST_MONO"); options.PublicIncludePaths.Add(Path.Combine(hostRuntime.Path, "include", "mono-2.0")); break; } diff --git a/Source/ThirdParty/rapidjson/prettywriter.h b/Source/ThirdParty/rapidjson/prettywriter.h index fe45df1d1..c66b6d734 100644 --- a/Source/ThirdParty/rapidjson/prettywriter.h +++ b/Source/ThirdParty/rapidjson/prettywriter.h @@ -108,7 +108,6 @@ public: } bool String(const Ch* str, SizeType length, bool copy = false) { - RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); return Base::EndValue(Base::WriteString(str, length)); diff --git a/Source/Tools/Flax.Build/Build/Builder.Projects.cs b/Source/Tools/Flax.Build/Build/Builder.Projects.cs index 59538364c..46925355c 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Projects.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Projects.cs @@ -192,6 +192,8 @@ namespace Flax.Build { // Pick the project format var projectFormats = new HashSet(); + if (Configuration.ProjectFormatVS2026) + projectFormats.Add(ProjectFormat.VisualStudio2026); if (Configuration.ProjectFormatVS2022) projectFormats.Add(ProjectFormat.VisualStudio2022); if (Configuration.ProjectFormatVS2019) @@ -209,8 +211,13 @@ namespace Flax.Build if (projectFormats.Count == 0) projectFormats.Add(Platform.BuildPlatform.DefaultProjectFormat); - // Always generate VS solution files for project (needed for C# Intellisense support) - projectFormats.Add(ProjectFormat.VisualStudio2022); + // Always generate VS solution files for project (needed for C# Intellisense support in other IDEs) + if (!projectFormats.Contains(ProjectFormat.VisualStudio2026) && + !projectFormats.Contains(ProjectFormat.VisualStudio2022) && + !projectFormats.Contains(ProjectFormat.VisualStudio)) + { + projectFormats.Add(ProjectFormat.VisualStudio2022); + } foreach (ProjectFormat projectFormat in projectFormats) GenerateProject(projectFormat); diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs index 947ac575c..f279e65d6 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs @@ -192,11 +192,18 @@ namespace Flax.Build { if (string.IsNullOrEmpty(path)) return string.Empty; - if (path.StartsWith(Globals.EngineRoot)) + path = Utilities.NormalizePath(path); + if (IsMacroPath(path, Globals.EngineRoot)) path = "$(EnginePath)" + path.Substring(Globals.EngineRoot.Length); - else if (path.StartsWith(projectPath)) + else if (IsMacroPath(path, projectPath)) path = "$(ProjectPath)" + path.Substring(projectPath.Length); - return Utilities.NormalizePath(path); + return path; + } + + private static bool IsMacroPath(string path, string root) + { + root = Utilities.NormalizePath(root); + return path == root || path.StartsWith(root + '/'); } } diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 1769eb059..79c1af75f 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -201,6 +201,12 @@ namespace Flax.Build [CommandLine("vs2022", "Generates Visual Studio 2022 project format files. Valid only with -genproject option.")] public static bool ProjectFormatVS2022 = false; + /// + /// Generates Visual Studio 2026 project format files. Valid only with -genproject option. + /// + [CommandLine("vs2026", "Generates Visual Studio 2026 project format files. Valid only with -genproject option.")] + public static bool ProjectFormatVS2026 = false; + /// /// Generates Visual Studio Code project format files. Valid only with -genproject option. /// diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs b/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs index 7b42486e2..447b91498 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs @@ -49,7 +49,8 @@ namespace Flax.Deps.Dependencies public override void Build(BuildOptions options) { var root = options.IntermediateFolder; - var version = "1.23.1"; + var version = "1.24.3"; + var configuration = "Release"; var dstIncludePath = Path.Combine(options.ThirdPartyFolder, "OpenAL"); foreach (var platform in options.Platforms) @@ -65,11 +66,9 @@ namespace Flax.Deps.Dependencies "OpenAL32.dll", }; - string configuration = "Release"; - // Get the source CloneGitRepo(root, "https://github.com/kcat/openal-soft.git"); - GitCheckout(root, "master", "d3875f333fb6abe2f39d82caca329414871ae53b"); // 1.23.1 + GitCheckout(root, "master", "dc7d7054a5b4f3bec1dc23a42fd616a0847af948"); // 1.24.3 // Build for Win64 and ARM64 foreach (var architecture in new[] { TargetArchitecture.x64, TargetArchitecture.ARM64 }) @@ -122,9 +121,16 @@ namespace Flax.Deps.Dependencies var envVars = new Dictionary { { "CC", "clang-" + Configuration.LinuxClangMinVer }, - { "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer } + { "CC_FOR_BUILD", "clang-" + Configuration.LinuxClangMinVer }, + { "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel }, }; - var config = "-DALSOFT_REQUIRE_ALSA=ON -DALSOFT_REQUIRE_OSS=ON -DALSOFT_REQUIRE_PORTAUDIO=ON -DALSOFT_REQUIRE_PULSEAUDIO=ON -DALSOFT_REQUIRE_JACK=ON -DALSOFT_EMBED_HRTF_DATA=YES"; + var config = $"-DALSOFT_REQUIRE_ALSA=ON " + + $"-DALSOFT_REQUIRE_OSS=ON " + + $"-DALSOFT_REQUIRE_PORTAUDIO=ON " + + $"-DALSOFT_REQUIRE_PULSEAUDIO=ON " + + $"-DALSOFT_REQUIRE_JACK=ON " + + $"-DALSOFT_REQUIRE_PIPEWIRE=ON " + + $"-DALSOFT_EMBED_HRTF_DATA=YES "; // Get the source var packagePath = Path.Combine(root, "package.zip"); @@ -138,8 +144,8 @@ namespace Flax.Deps.Dependencies SetupDirectory(buildDir, true); // Build for Linux - Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLIBTYPE=STATIC " + config + " ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); + Utilities.Run("cmake", $"-G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE={configuration} -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLIBTYPE=STATIC {config} ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); + BuildCmake(buildDir, configuration, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -151,7 +157,11 @@ namespace Flax.Deps.Dependencies { "libopenal.a", }; - var config = "-DALSOFT_REQUIRE_OBOE=OFF -DALSOFT_REQUIRE_OPENSL=ON -DALSOFT_EMBED_HRTF_DATA=YES"; + var envVars = new Dictionary + { + { "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel }, + }; + var config = " -DALSOFT_REQUIRE_OBOE=OFF -DALSOFT_REQUIRE_OPENSL=ON -DALSOFT_EMBED_HRTF_DATA=YES"; // Get the source var packagePath = Path.Combine(root, "package.zip"); @@ -174,8 +184,8 @@ namespace Flax.Deps.Dependencies SetupDirectory(buildDir, true); // Build - RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - BuildCmake(buildDir); + RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=" + configuration + config, envVars); + BuildCmake(buildDir, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -187,7 +197,11 @@ namespace Flax.Deps.Dependencies { "libopenal.a", }; - var config = "-DALSOFT_REQUIRE_COREAUDIO=ON -DALSOFT_EMBED_HRTF_DATA=YES"; + var envVars = new Dictionary + { + { "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel }, + }; + var config = " -DALSOFT_REQUIRE_COREAUDIO=ON -DALSOFT_EMBED_HRTF_DATA=YES"; // Get the source var packagePath = Path.Combine(root, "package.zip"); @@ -203,8 +217,8 @@ namespace Flax.Deps.Dependencies foreach (var architecture in new[] { TargetArchitecture.x64, TargetArchitecture.ARM64 }) { SetupDirectory(buildDir, true); - RunCmake(buildDir, platform, architecture, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - BuildCmake(buildDir); + RunCmake(buildDir, platform, architecture, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=" + configuration + config, envVars); + BuildCmake(buildDir, envVars); var depsFolder = GetThirdPartyFolder(options, platform, architecture); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -217,7 +231,11 @@ namespace Flax.Deps.Dependencies { "libopenal.a", }; - var config = "-DALSOFT_REQUIRE_COREAUDIO=ON -DALSOFT_EMBED_HRTF_DATA=YES"; + var envVars = new Dictionary + { + { "CMAKE_BUILD_PARALLEL_LEVEL", CmakeBuildParallel }, + }; + var config = " -DALSOFT_REQUIRE_COREAUDIO=ON -DALSOFT_EMBED_HRTF_DATA=YES"; // Get the source var packagePath = Path.Combine(root, "package.zip"); @@ -233,8 +251,8 @@ namespace Flax.Deps.Dependencies // Build for iOS SetupDirectory(buildDir, true); - RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_SYSTEM_NAME=iOS -DALSOFT_OSX_FRAMEWORK=ON -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - BuildCmake(buildDir); + RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_SYSTEM_NAME=iOS -DALSOFT_OSX_FRAMEWORK=ON -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=" + configuration + config, envVars); + BuildCmake(buildDir, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index a9fe82b63..479911943 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -290,6 +290,21 @@ namespace Flax.Deps Utilities.Run("git", $"reset --hard {commit}", null, path, Utilities.RunOptions.DefaultTool); } + /// + /// Gets the maximum concurrency level for a cmake command. See CMAKE_BUILD_PARALLEL_LEVEL or -j docs. + /// + public static string CmakeBuildParallel => Math.Min(Math.Max(1, (int)(Environment.ProcessorCount * Configuration.ConcurrencyProcessorScale)), Configuration.MaxConcurrency).ToString(); + + /// + /// Builds the cmake project. + /// + /// The path. + /// Custom environment variables to pass to the child process. + public static void BuildCmake(string path, Dictionary envVars) + { + BuildCmake(path, "Release", envVars); + } + /// /// Builds the cmake project. /// diff --git a/Source/Tools/Flax.Build/Deps/Downloader.cs b/Source/Tools/Flax.Build/Deps/Downloader.cs index 4b8c77da0..57da4a2ee 100644 --- a/Source/Tools/Flax.Build/Deps/Downloader.cs +++ b/Source/Tools/Flax.Build/Deps/Downloader.cs @@ -14,6 +14,7 @@ namespace Flax.Deps /// static class Downloader { + private static bool IgnoreSSL = false; private const string GoogleDriveDomain = "drive.google.com"; private const string GoogleDriveDomain2 = "https://drive.google.com"; @@ -54,7 +55,7 @@ namespace Flax.Deps { if (httpClient == null) { - using (httpClient = new HttpClient()) + using (httpClient = GetHttpClient()) { return DownloadFileFromUrlToPathRaw(url, path, httpClient); } @@ -130,7 +131,7 @@ namespace Flax.Deps // You can comment the statement below if the provided url is guaranteed to be in the following format: // https://drive.google.com/uc?id=FILEID&export=download url = GetGoogleDriveDownloadLinkFromUrl(url); - using (var httpClient = new HttpClient()) + using (var httpClient = GetHttpClient()) { FileInfo downloadedFile; @@ -209,5 +210,18 @@ namespace Flax.Deps return string.Format("https://drive.google.com/uc?id={0}&export=download", url.Substring(index, closingIndex - index)); } + + private static HttpClient GetHttpClient() + { + if (IgnoreSSL) + { + Log.Warning("Accessing HTTP with SSL certificate validation disabled!"); + var handler = new HttpClientHandler(); + handler.ClientCertificateOptions = ClientCertificateOption.Manual; + handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true; + return new HttpClient(handler); + } + return new HttpClient(); + } } } diff --git a/Source/Tools/Flax.Build/Platforms/GDK/GDKPlatform.cs b/Source/Tools/Flax.Build/Platforms/GDK/GDKPlatform.cs index 9313c65b0..422299c79 100644 --- a/Source/Tools/Flax.Build/Platforms/GDK/GDKPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/GDK/GDKPlatform.cs @@ -32,8 +32,11 @@ namespace Flax.Build.Platforms if (!toolsets.ContainsKey(WindowsPlatformToolset.v141) && !toolsets.ContainsKey(WindowsPlatformToolset.v142) && !toolsets.ContainsKey(WindowsPlatformToolset.v143) && - !toolsets.ContainsKey(WindowsPlatformToolset.v144)) + !toolsets.ContainsKey(WindowsPlatformToolset.v144) && + !toolsets.ContainsKey(WindowsPlatformToolset.v145)) + { _hasRequiredSDKsInstalled = false; + } } } } diff --git a/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs b/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs index 6d8b9e5b1..529e75eda 100644 --- a/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs @@ -31,7 +31,12 @@ namespace Flax.Build.Platforms } // Visual Studio 2017+ supported only - var visualStudio = VisualStudioInstance.GetInstances().FirstOrDefault(x => x.Version == VisualStudioVersion.VisualStudio2017 || x.Version == VisualStudioVersion.VisualStudio2019 || x.Version == VisualStudioVersion.VisualStudio2022); + var visualStudio = VisualStudioInstance.GetInstances().FirstOrDefault(x => + x.Version == VisualStudioVersion.VisualStudio2017 || + x.Version == VisualStudioVersion.VisualStudio2019 || + x.Version == VisualStudioVersion.VisualStudio2022 || + x.Version == VisualStudioVersion.VisualStudio2026 + ); if (visualStudio == null) _hasRequiredSDKsInstalled = false; @@ -46,7 +51,8 @@ namespace Flax.Build.Platforms if (!toolsets.ContainsKey(WindowsPlatformToolset.v141) && !toolsets.ContainsKey(WindowsPlatformToolset.v142) && !toolsets.ContainsKey(WindowsPlatformToolset.v143) && - !toolsets.ContainsKey(WindowsPlatformToolset.v144)) + !toolsets.ContainsKey(WindowsPlatformToolset.v144) && + !toolsets.ContainsKey(WindowsPlatformToolset.v145)) { _hasRequiredSDKsInstalled = false; } diff --git a/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs b/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs index 983ac37d2..5458c5d7d 100644 --- a/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs @@ -29,7 +29,12 @@ namespace Flax.Build.Platforms public UWPToolchain(UWPPlatform platform, TargetArchitecture architecture, WindowsPlatformToolset toolsetVer = WindowsPlatformToolset.Latest, WindowsPlatformSDK sdkVer = WindowsPlatformSDK.Latest) : base(platform, architecture, toolsetVer, sdkVer) { - var visualStudio = VisualStudioInstance.GetInstances().FirstOrDefault(x => x.Version == VisualStudioVersion.VisualStudio2017 || x.Version == VisualStudioVersion.VisualStudio2019 || x.Version == VisualStudioVersion.VisualStudio2022); + var visualStudio = VisualStudioInstance.GetInstances().FirstOrDefault(x => + x.Version == VisualStudioVersion.VisualStudio2017 || + x.Version == VisualStudioVersion.VisualStudio2019 || + x.Version == VisualStudioVersion.VisualStudio2022 || + x.Version == VisualStudioVersion.VisualStudio2026 + ); if (visualStudio == null) throw new Exception("Missing Visual Studio 2017 or newer. It's required to build for UWP."); _usingDirs.Add(Path.Combine(visualStudio.Path, "VC", "vcpackages")); diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs index 02c5ce8f0..a78f8c24f 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs @@ -40,7 +40,8 @@ namespace Flax.Build.Platforms !toolsets.ContainsKey(WindowsPlatformToolset.v141) && !toolsets.ContainsKey(WindowsPlatformToolset.v142) && !toolsets.ContainsKey(WindowsPlatformToolset.v143) && - !toolsets.ContainsKey(WindowsPlatformToolset.v144)) + !toolsets.ContainsKey(WindowsPlatformToolset.v144) && + !toolsets.ContainsKey(WindowsPlatformToolset.v145)) { Log.Warning("Missing MSVC toolset v140 or later (VS 2015 or later C++ build tools). Cannot build for Windows platform."); _hasRequiredSDKsInstalled = false; diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs index 3cdc2f44b..26afcd894 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs @@ -54,6 +54,11 @@ namespace Flax.Build.Platforms /// Visual Studio 2022 (v17.10 and later) /// v144 = 144, + + /// + /// Visual Studio 2026 + /// + v145 = 145, } /// @@ -252,6 +257,8 @@ namespace Flax.Build.Platforms _toolsets[WindowsPlatformToolset.v143] = toolset; else if (version.Major == 14 && version.Minor / 10 == 4) _toolsets[WindowsPlatformToolset.v144] = toolset; + else if (version.Major == 14 && version.Minor / 10 == 5) + _toolsets[WindowsPlatformToolset.v145] = toolset; else Log.Warning("Found Unsupported MSVC toolset version: " + version); } @@ -287,11 +294,12 @@ namespace Flax.Build.Platforms } } - // Visual Studio 2017-2022 - multiple instances + // Visual Studio 2017 or later - multiple instances foreach (var vs in vsInstances.Where(x => x.Version == VisualStudioVersion.VisualStudio2017 || x.Version == VisualStudioVersion.VisualStudio2019 || - x.Version == VisualStudioVersion.VisualStudio2022 + x.Version == VisualStudioVersion.VisualStudio2022 || + x.Version == VisualStudioVersion.VisualStudio2026 )) { FindMsvcToolsets(Path.Combine(vs.Path, "VC", "Tools", "MSVC")); @@ -469,6 +477,7 @@ namespace Flax.Build.Platforms case WindowsPlatformToolset.v142: case WindowsPlatformToolset.v143: case WindowsPlatformToolset.v144: + case WindowsPlatformToolset.v145: { string hostFolder = hostArchitecture == TargetArchitecture.x86 ? "HostX86" : $"Host{hostArchitecture.ToString().ToLower()}"; string nativeCompilerPath = Path.Combine(vcToolChainDir, "bin", hostFolder, architecture.ToString().ToLower(), "cl.exe"); diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs index bd53d0c65..0ce3c2d79 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs @@ -89,7 +89,11 @@ namespace Flax.Build.Platforms // Pick the newest installed Visual Studio version if using the default toolset if (toolsetVer == WindowsPlatformToolset.Default) { - if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2022)) + if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2026)) + { + toolsetVer = WindowsPlatformToolset.v145; + } + else if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2022)) { if (toolsets.Keys.Contains(WindowsPlatformToolset.v144)) { @@ -206,6 +210,7 @@ namespace Flax.Build.Platforms case WindowsPlatformToolset.v142: case WindowsPlatformToolset.v143: case WindowsPlatformToolset.v144: + case WindowsPlatformToolset.v145: { switch (Architecture) { @@ -392,6 +397,7 @@ namespace Flax.Build.Platforms var vcToolChainDir = toolsets[Toolset]; switch (Toolset) { + case WindowsPlatformToolset.v145: case WindowsPlatformToolset.v144: case WindowsPlatformToolset.v143: case WindowsPlatformToolset.v142: diff --git a/Source/Tools/Flax.Build/Projects/ProjectFormat.cs b/Source/Tools/Flax.Build/Projects/ProjectFormat.cs index 5f5017ced..3e5fd3a70 100644 --- a/Source/Tools/Flax.Build/Projects/ProjectFormat.cs +++ b/Source/Tools/Flax.Build/Projects/ProjectFormat.cs @@ -37,6 +37,11 @@ namespace Flax.Build.Projects /// VisualStudio2022, + /// + /// Visual Studio 2026. + /// + VisualStudio2026, + /// /// Visual Studio Code. /// diff --git a/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs index fbbeca14d..a6e5b79ad 100644 --- a/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs @@ -84,7 +84,11 @@ namespace Flax.Build.Projects // Pick the newest installed Visual Studio version if (format == ProjectFormat.VisualStudio) { - if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2022)) + if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2026)) + { + format = ProjectFormat.VisualStudio2026; + } + else if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2022)) { format = ProjectFormat.VisualStudio2022; } @@ -113,6 +117,7 @@ namespace Flax.Build.Projects case ProjectFormat.VisualStudio2017: case ProjectFormat.VisualStudio2019: case ProjectFormat.VisualStudio2022: + case ProjectFormat.VisualStudio2026: { VisualStudioVersion vsVersion; switch (format) @@ -129,6 +134,9 @@ namespace Flax.Build.Projects case ProjectFormat.VisualStudio2022: vsVersion = VisualStudioVersion.VisualStudio2022; break; + case ProjectFormat.VisualStudio2026: + vsVersion = VisualStudioVersion.VisualStudio2026; + break; default: throw new ArgumentOutOfRangeException(nameof(format), format, null); } switch (type) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/CSProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/CSProjectGenerator.cs index 35bc7b0ac..99e3b083b 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/CSProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/CSProjectGenerator.cs @@ -50,7 +50,9 @@ namespace Flax.Build.Projects.VisualStudio projectTypes = ProjectTypeGuids.ToOption(ProjectTypeGuids.FlaxVS) + ';' + projectTypes; // Try to reuse the existing project guid from solution file - vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name); + vsProject.ProjectGuid = GetProjectGuid(vsProject.Path, vsProject.Name); + if (vsProject.ProjectGuid == Guid.Empty) + vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name); if (vsProject.ProjectGuid == Guid.Empty) vsProject.ProjectGuid = Guid.NewGuid(); diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs index f126bd3ef..671cfb5e8 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs @@ -55,7 +55,9 @@ namespace Flax.Build.Projects.VisualStudio } // Try to reuse the existing project guid from solution file - vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name); + vsProject.ProjectGuid = GetProjectGuid(vsProject.Path, vsProject.Name); + if (vsProject.ProjectGuid == Guid.Empty) + vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name); if (vsProject.ProjectGuid == Guid.Empty) vsProject.ProjectGuid = Guid.NewGuid(); diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs index 2d7b23ce5..3791dfa21 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs @@ -28,6 +28,7 @@ namespace Flax.Build.Projects.VisualStudio case VisualStudioVersion.VisualStudio2017: return "v141"; case VisualStudioVersion.VisualStudio2019: return "v142"; case VisualStudioVersion.VisualStudio2022: return "v143"; + case VisualStudioVersion.VisualStudio2026: return "v145"; } return string.Empty; } diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs index b3b67482f..16e5fee80 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs @@ -128,6 +128,8 @@ namespace Flax.Build.Projects.VisualStudio version = VisualStudioVersion.VisualStudio2019; else if (displayName.Contains("2022")) version = VisualStudioVersion.VisualStudio2022; + else if (displayName.Contains("2026")) + version = VisualStudioVersion.VisualStudio2026; else { Log.Warning(string.Format("Unknown Visual Studio installation. Display name: {0}", displayName)); diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs index 337f4497d..d657f6247 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs @@ -128,6 +128,7 @@ namespace Flax.Build.Projects.VisualStudio case VisualStudioVersion.VisualStudio2017: return "15.0"; case VisualStudioVersion.VisualStudio2019: return "16.0"; case VisualStudioVersion.VisualStudio2022: return "17.0"; + case VisualStudioVersion.VisualStudio2026: return "18.0"; } return string.Empty; @@ -193,7 +194,7 @@ namespace Flax.Build.Projects.VisualStudio } /// - public override string SolutionFileExtension => "sln"; + public override string SolutionFileExtension => /*Version >= VisualStudioVersion.VisualStudio2026 ? "slnx" :*/ "sln"; /// public override Project CreateProject() @@ -277,6 +278,20 @@ namespace Flax.Build.Projects.VisualStudio } } + if (Version >= VisualStudioVersion.VisualStudio2026) + GenerateXmlSolution(solution); + else + GenerateAsciiSolution(solution); + } + + private void GenerateXmlSolution(Solution solution) + { + // TODO: Generate the solution file in new format + GenerateAsciiSolution(solution); + } + + private void GenerateAsciiSolution(Solution solution) + { // Try to extract solution folder info from the existing solution file to make random IDs stable var solutionId = Guid.NewGuid(); var folderIds = new Dictionary(); @@ -313,7 +328,7 @@ namespace Flax.Build.Projects.VisualStudio var projects = solution.Projects.Cast().ToArray(); // Header - if (Version == VisualStudioVersion.VisualStudio2022) + if (Version >= VisualStudioVersion.VisualStudio2022) { vcSolutionFileContent.AppendLine("Microsoft Visual Studio Solution File, Format Version 12.00"); vcSolutionFileContent.AppendLine("# Visual Studio Version 17"); diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioVersion.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioVersion.cs index 236aa5d7e..e7fc03c71 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioVersion.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioVersion.cs @@ -26,5 +26,10 @@ namespace Flax.Build.Projects.VisualStudio /// The Visual Studio 2022. /// VisualStudio2022, + + /// + /// The Visual Studio 2026. + /// + VisualStudio2026, } } diff --git a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs index c92ae6986..12b9d1e4e 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs @@ -648,6 +648,7 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddField("**/Screenshots", true); json.AddField("**/Output", true); json.AddField("**/*.flax", true); + json.AddField("**/Plugins", true); json.EndObject(); // Extension settings @@ -683,9 +684,15 @@ namespace Flax.Build.Projects.VisualStudioCode json.EndObject(); // Referenced projects outside the current project (including engine too) - foreach (var project in Globals.Project.GetAllProjects()) + var projects = Globals.Project.GetAllProjects(); + // Move Engine to last for organizational purposes. + var engineProject = projects.First(x => x.Name == "Flax"); + var projectsWithoutEngine = projects.Where(x => x.Name != "Flax"); + projectsWithoutEngine = projectsWithoutEngine.OrderBy(x => x.Name); + var sortedProjects = projectsWithoutEngine.Concat([engineProject]); + foreach (var project in sortedProjects) { - if (!project.ProjectFolderPath.Contains(Globals.Project.ProjectFolderPath)) + if (!project.ProjectFolderPath.Equals(Globals.Project.ProjectFolderPath)) { json.BeginObject(); {