Compare commits
383 Commits
sdl_platfo
...
emscripten
| Author | SHA1 | Date | |
|---|---|---|---|
| 578287f3bf | |||
|
|
489c4a3661 | ||
|
|
43dca143fa | ||
|
|
6bd13feba6 | ||
|
|
d1557e5292 | ||
|
|
6f13a33be2 | ||
|
|
4ccf969f7a | ||
|
|
3d206e06d0 | ||
|
|
25e90deed6 | ||
|
|
7bc687194f | ||
|
|
8a760dc1e2 | ||
|
|
fc0b885a14 | ||
|
|
f12ad5c874 | ||
|
|
fd0584b406 | ||
|
|
374f6e40bb | ||
|
|
9c9e17a9d9 | ||
|
|
865a26cbbe | ||
|
|
56e825cad4 | ||
|
|
1df608e902 | ||
|
|
07f031e4c5 | ||
|
|
06c31a39f2 | ||
|
|
2a6e38e020 | ||
|
|
cc69e5d966 | ||
|
|
d68969dbe2 | ||
|
|
c4d20f06ee | ||
|
|
3c5c6f9883 | ||
|
|
8e7dc2a91e | ||
|
|
4ddbc8ba5c | ||
|
|
15f379e87f | ||
|
|
d4a7b3074e | ||
|
|
a3492e59ef | ||
|
|
515ad56fa2 | ||
|
|
ebd20dd816 | ||
|
|
019a9f6089 | ||
|
|
273b110db4 | ||
|
|
0bea701a83 | ||
|
|
ee22b9dc25 | ||
|
|
a1096aaf92 | ||
|
|
885ee15767 | ||
|
|
c978ab2b84 | ||
|
|
f045b5b6b6 | ||
|
|
c51a023e61 | ||
|
|
645df4fb06 | ||
|
|
b53028782f | ||
|
|
ef551c36ae | ||
|
|
e851efa0a8 | ||
| 0084bc051c | |||
|
|
9c8023d64f | ||
|
|
6d02f5d9da | ||
|
|
1f9f281c31 | ||
|
|
846b64048f | ||
|
|
55f73b6cf7 | ||
|
|
0f6c1aea62 | ||
|
|
d2ee61ef8d | ||
|
|
a1399c5157 | ||
|
|
7b7a92758f | ||
|
|
bd300651ec | ||
|
|
a2b0d0714e | ||
|
|
3d66316716 | ||
|
|
9c32f978fb | ||
|
|
ed5ad91a32 | ||
|
|
ecddb8aae5 | ||
|
|
a855b17cc0 | ||
|
|
27dd1bda25 | ||
|
|
4afd9fd8df | ||
|
|
73c19b278f | ||
|
|
b4cb1028ed | ||
|
|
4a7f1a5fde | ||
|
|
5d0fdc8313 | ||
|
|
70b324cdec | ||
|
|
20516bb8bc | ||
|
|
c18b9163ca | ||
|
|
db5b65beac | ||
|
|
78e5baf6a5 | ||
|
|
4833c19366 | ||
|
|
65fd22f5b6 | ||
|
|
f57df83d26 | ||
|
|
66894b71fa | ||
|
|
7e9ee0610a | ||
|
|
f733611213 | ||
|
|
780e78f056 | ||
|
|
4d447b7544 | ||
|
|
9a44902949 | ||
|
|
e84b5410ec | ||
|
|
9ac19cbd2f | ||
|
|
39a2bc2535 | ||
|
|
15771355cb | ||
|
|
f3111e855d | ||
|
|
3c6838ee35 | ||
|
|
36ab08e60d | ||
|
|
834c4553b2 | ||
|
|
5a95336601 | ||
|
|
f26fae2daf | ||
|
|
20df4289c2 | ||
|
|
217701ae05 | ||
|
|
f1509bab28 | ||
|
|
30fdd7336e | ||
|
|
3b120cc5a4 | ||
|
|
4cf0c38940 | ||
|
|
0f383d2fc6 | ||
| 483df22929 | |||
|
|
07f21a1520 | ||
| f870fc3ae2 | |||
|
|
bbb5354e9c | ||
|
|
21e2c830e5 | ||
|
|
c828c90161 | ||
|
|
f725f4c0b9 | ||
|
|
1535f95cf1 | ||
|
|
b1f85b7462 | ||
|
|
3a0af54f48 | ||
|
|
4e3e9386cc | ||
|
|
449fc597b5 | ||
|
|
0e91a2d25b | ||
|
|
aba995a42f | ||
|
|
bf0c7fe0dc | ||
|
|
2ab8b9dd55 | ||
|
|
e1ffdee57a | ||
|
|
7c44767d4d | ||
|
|
87ccaa9dd8 | ||
|
|
e8c2f18a4d | ||
|
|
6b36543717 | ||
|
|
bb2a883dc7 | ||
|
|
be7e88de36 | ||
|
|
4a1490f0b1 | ||
|
|
e0d0acc33c | ||
|
|
e2f2d3e6f6 | ||
|
|
afc04dc41c | ||
|
|
bdfa503c05 | ||
|
|
205a8b2ebe | ||
|
|
d18c245730 | ||
|
|
e4eb064562 | ||
|
|
9fc9382e58 | ||
|
|
2bf9efaf30 | ||
|
|
528b4c89ce | ||
|
|
277dabc8b4 | ||
|
|
9a5bc444ba | ||
|
|
e834fc5a42 | ||
|
|
6b87985a44 | ||
|
|
a65a74b866 | ||
|
|
b2124201d5 | ||
|
|
29b8326042 | ||
|
|
81bfa6edc9 | ||
|
|
8ed6a92022 | ||
|
|
c9d16e16cc | ||
|
|
d9f9401c5a | ||
|
|
1e9918b9cc | ||
|
|
6c84b7a259 | ||
|
|
43b337e163 | ||
|
|
45306ca20e | ||
|
|
259d93f95c | ||
|
|
61b6aeb252 | ||
|
|
d694c35db4 | ||
|
|
f105d6f84f | ||
|
|
b1b6953200 | ||
|
|
fa428e343b | ||
|
|
dbbb67f398 | ||
|
|
a9bddfa784 | ||
|
|
f9b784a42a | ||
|
|
d47bd5d6e7 | ||
|
|
e1013aec94 | ||
|
|
1c294059df | ||
|
|
305296883d | ||
|
|
a7016d1186 | ||
|
|
004e02af73 | ||
|
|
143d714037 | ||
|
|
da8376bba1 | ||
|
|
f773a0755d | ||
|
|
d8343dae8e | ||
|
|
b09fbe2d9b | ||
|
|
6dbfd25bdb | ||
|
|
ecfd03f79c | ||
|
|
66a295d5af | ||
|
|
d7458d81a5 | ||
|
|
cc5e4c19e1 | ||
|
|
0c5cb59875 | ||
|
|
85ed0ecb06 | ||
|
|
95b9392f51 | ||
|
|
c7c1bbe35f | ||
|
|
192d3d1a8e | ||
|
|
877d57681d | ||
|
|
0a9bc084f4 | ||
|
|
ec4f8ce239 | ||
|
|
d049a16882 | ||
|
|
ee75cab73e | ||
|
|
0072e21ffa | ||
|
|
f44dde89db | ||
|
|
e6fd761b80 | ||
|
|
62a378e01a | ||
|
|
e67b705397 | ||
|
|
847f6411e7 | ||
|
|
0d7c04682d | ||
|
|
baf068330c | ||
|
|
593646061e | ||
|
|
9ac231c403 | ||
|
|
d2d7a871ce | ||
|
|
b172b08782 | ||
|
|
18778aa511 | ||
|
|
b7e32e13ab | ||
|
|
610c76578b | ||
|
|
e721fbd89f | ||
|
|
ff2c5290b5 | ||
|
|
2b4dc97a97 | ||
|
|
14842183f2 | ||
|
|
b4b13d8dd4 | ||
|
|
e3d1e8a5ea | ||
|
|
d9f90f726b | ||
|
|
e0062a6ff1 | ||
|
|
e494c9ec76 | ||
|
|
2501095500 | ||
|
|
3cfc5db54a | ||
|
|
840835fad2 | ||
|
|
41f136ce0f | ||
|
|
32cae3aacd | ||
|
|
832c524c3c | ||
|
|
a18ca9a4ad | ||
|
|
05e7e6630c | ||
|
|
788d8660b8 | ||
|
|
ab806b2a9b | ||
|
|
610ba00915 | ||
|
|
e60bd165f4 | ||
|
|
223d4f64eb | ||
|
|
827ad85651 | ||
|
|
69c5d65318 | ||
|
|
b834dddb11 | ||
|
|
baddfec6d1 | ||
|
|
fc2f56aca6 | ||
|
|
0364fd629b | ||
|
|
5dbaf3f94e | ||
|
|
c5b7ea9c44 | ||
|
|
7b856fdc95 | ||
|
|
890df65970 | ||
|
|
ab6dfca36e | ||
|
|
72bb2dd932 | ||
|
|
ca09852898 | ||
|
|
e21cb9154a | ||
|
|
af124ce163 | ||
|
|
c28381fb09 | ||
|
|
973ff0efa0 | ||
|
|
27896b6410 | ||
|
|
4bb9de21b4 | ||
|
|
890538c667 | ||
|
|
4b9fa0dcf5 | ||
|
|
14d1b7dd24 | ||
|
|
6788844270 | ||
|
|
b2f2537338 | ||
|
|
450b998a29 | ||
|
|
688d9c77cb | ||
|
|
d71ea5a72b | ||
|
|
01e3ece2af | ||
|
|
afc65f7557 | ||
|
|
d60484b917 | ||
| feceb4e00f | |||
| 67b33a575a | |||
|
|
76b869146d | ||
|
|
32e725392b | ||
|
|
0975ac2a25 | ||
|
|
cf3bcc4549 | ||
|
|
11ea889fa9 | ||
|
|
c5a28a5734 | ||
|
|
6c79a17c7a | ||
|
|
b24d98df9e | ||
|
|
400e2f1b0e | ||
|
|
22e6139ca3 | ||
|
|
859fa16a74 | ||
|
|
8facb46def | ||
|
|
b87f8b96e1 | ||
|
|
37df16a3e4 | ||
|
|
ce45fa3d54 | ||
|
|
7f56d9456b | ||
|
|
1cad2489a3 | ||
|
|
7cdc2456cd | ||
|
|
6b0ee3eeed | ||
|
|
57330e39ca | ||
|
|
af29f2f3dc | ||
|
|
1bdb577b60 | ||
|
|
329ea1c9b4 | ||
|
|
728da6354f | ||
|
|
d5456d6eb3 | ||
|
|
e65714988f | ||
|
|
4e4df736f9 | ||
|
|
5bfe5b0035 | ||
|
|
b30553ea65 | ||
|
|
2550763808 | ||
|
|
6f6dd2f4a3 | ||
|
|
c30d457b1c | ||
|
|
b786fa1c22 | ||
|
|
bbcbe305a8 | ||
|
|
222df16f11 | ||
|
|
8b924d13c1 | ||
|
|
66e25c81b0 | ||
|
|
e12f99ee53 | ||
|
|
387f0cf457 | ||
|
|
f11acdf5db | ||
|
|
3af7dddcc2 | ||
|
|
543e2ecd13 | ||
| 35f8051a62 | |||
| 4453453d46 | |||
|
|
23f5f4d85f | ||
|
|
90a21696f6 | ||
|
|
fa38f0ac91 | ||
| e3f5af530b | |||
|
|
38d8832468 | ||
|
|
c68aa3b371 | ||
| d031649bbd | |||
| 21b8d1838d | |||
| c8ee2fc155 | |||
|
|
dc22fa4061 | ||
| 3eb690fe58 | |||
| 52e2327527 | |||
| f95cbb0e52 | |||
| 518a19c857 | |||
| c0b54be692 | |||
|
|
c2c92eba82 | ||
| d64c28f672 | |||
| 2a959d0531 | |||
|
|
4504d0ae96 | ||
| f14ba6ace6 | |||
| 518f9dc9dc | |||
| 8db29a30e0 | |||
|
|
0e76585709 | ||
|
|
8bf51512ac | ||
|
|
779e8e7169 | ||
|
|
3c8b80152b | ||
|
|
f280412ef4 | ||
| 1327fa40cb | |||
| b70ab01308 | |||
| ae03bc2dd2 | |||
| 5cd27032b4 | |||
| 7445064d97 | |||
|
|
e47fc5a54a | ||
|
|
26e24769be | ||
|
|
394860656a | ||
|
|
b07d74d28d | ||
|
|
dacb3b0891 | ||
|
|
a8db0086b1 | ||
|
|
e46b6d5b06 | ||
|
|
dfc8c1fac2 | ||
|
|
f8de118288 | ||
|
|
887311d1f1 | ||
|
|
f8e4f54c77 | ||
| ea20dc6da0 | |||
| 9becddd84f | |||
| b08c765400 | |||
| afd59d7eb3 | |||
| 47cdd0582c | |||
| af54d04f9d | |||
| 1d2b3bc858 | |||
| 4b552563be | |||
| ebd929176c | |||
| 430e685a7c | |||
| d5bd857c45 | |||
| b8b9ba3069 | |||
| 84c79d5192 | |||
| 028f3a7871 | |||
| 0c462315f0 | |||
| 26261a2090 | |||
|
|
b5de4d78ad | ||
|
|
0913e6f738 | ||
|
|
99c26ff9af | ||
|
|
a2d91d989d | ||
|
|
881154e9f4 | ||
|
|
5ec2476aec | ||
|
|
79351f0c4d | ||
|
|
25744986a3 | ||
|
|
48100cf9fc | ||
|
|
76f0768b99 | ||
|
|
b2b855200f | ||
|
|
241a8bc764 | ||
|
|
13dd80d429 | ||
|
|
6e9902a966 | ||
|
|
fd1e0a4e80 | ||
|
|
b130b81863 | ||
|
|
b38a7e6eb2 | ||
|
|
4f3f1cd163 | ||
|
|
4d77646f26 | ||
|
|
187592b673 | ||
|
|
215467ae42 | ||
|
|
facd7d39dc | ||
|
|
6810e5f2a4 | ||
|
|
ee6fae8956 | ||
|
|
bb6c3233d2 | ||
|
|
499228cc98 | ||
|
|
f2699892e0 |
3
.github/workflows/build_linux.yml
vendored
3
.github/workflows/build_linux.yml
vendored
@@ -16,7 +16,8 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
|
|||||||
6
.github/workflows/cd.yml
vendored
6
.github/workflows/cd.yml
vendored
@@ -87,7 +87,8 @@ jobs:
|
|||||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
@@ -118,7 +119,8 @@ jobs:
|
|||||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
|
|||||||
3
.github/workflows/tests.yml
vendored
3
.github/workflows/tests.yml
vendored
@@ -28,7 +28,8 @@ jobs:
|
|||||||
git lfs pull
|
git lfs pull
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8
|
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Redirect to our own Git LFS server
|
# Redirect to our own Git LFS server
|
||||||
[lfs]
|
[lfs]
|
||||||
url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
||||||
locksverify = false
|
locksverify = false
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,8 +4,8 @@
|
|||||||
#define MAX_LOCAL_LIGHTS 4
|
#define MAX_LOCAL_LIGHTS 4
|
||||||
@1// Forward Shading: Includes
|
@1// Forward Shading: Includes
|
||||||
#include "./Flax/LightingCommon.hlsl"
|
#include "./Flax/LightingCommon.hlsl"
|
||||||
#if USE_REFLECTIONS
|
|
||||||
#include "./Flax/ReflectionsCommon.hlsl"
|
#include "./Flax/ReflectionsCommon.hlsl"
|
||||||
|
#if USE_REFLECTIONS
|
||||||
#define MATERIAL_REFLECTIONS_SSR 1
|
#define MATERIAL_REFLECTIONS_SSR 1
|
||||||
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
||||||
#include "./Flax/SSR.hlsl"
|
#include "./Flax/SSR.hlsl"
|
||||||
@@ -14,11 +14,13 @@
|
|||||||
#include "./Flax/Lighting.hlsl"
|
#include "./Flax/Lighting.hlsl"
|
||||||
#include "./Flax/ShadowsSampling.hlsl"
|
#include "./Flax/ShadowsSampling.hlsl"
|
||||||
#include "./Flax/ExponentialHeightFog.hlsl"
|
#include "./Flax/ExponentialHeightFog.hlsl"
|
||||||
|
#include "./Flax/VolumetricFog.hlsl"
|
||||||
@2// Forward Shading: Constants
|
@2// Forward Shading: Constants
|
||||||
LightData DirectionalLight;
|
LightData DirectionalLight;
|
||||||
LightData SkyLight;
|
LightData SkyLight;
|
||||||
ProbeData EnvironmentProbe;
|
EnvProbeData EnvironmentProbe;
|
||||||
ExponentialHeightFogData ExponentialHeightFog;
|
ExponentialHeightFogData ExponentialHeightFog;
|
||||||
|
VolumetricFogData VolumetricFog;
|
||||||
float3 Dummy2;
|
float3 Dummy2;
|
||||||
uint LocalLightsCount;
|
uint LocalLightsCount;
|
||||||
LightData LocalLights[MAX_LOCAL_LIGHTS];
|
LightData LocalLights[MAX_LOCAL_LIGHTS];
|
||||||
@@ -28,12 +30,14 @@ TextureCube SkyLightTexture : register(t__SRV__);
|
|||||||
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
||||||
Texture2D<float> ShadowMap : register(t__SRV__);
|
Texture2D<float> ShadowMap : register(t__SRV__);
|
||||||
Texture3D VolumetricFogTexture : register(t__SRV__);
|
Texture3D VolumetricFogTexture : register(t__SRV__);
|
||||||
|
Texture2D PreIntegratedGF : register(t__SRV__);
|
||||||
@4// Forward Shading: Utilities
|
@4// Forward Shading: Utilities
|
||||||
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
|
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
|
||||||
LightData GetDirectionalLight() { return DirectionalLight; }
|
LightData GetDirectionalLight() { return DirectionalLight; }
|
||||||
LightData GetSkyLight() { return SkyLight; }
|
LightData GetSkyLight() { return SkyLight; }
|
||||||
ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
EnvProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
||||||
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
||||||
|
VolumetricFogData GetVolumetricFog() { return VolumetricFog; }
|
||||||
uint GetLocalLightsCount() { return LocalLightsCount; }
|
uint GetLocalLightsCount() { return LocalLightsCount; }
|
||||||
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
||||||
@5// Forward Shading: Shaders
|
@5// Forward Shading: Shaders
|
||||||
@@ -108,7 +112,8 @@ void PS_Forward(
|
|||||||
|
|
||||||
// Calculate reflections
|
// Calculate reflections
|
||||||
#if USE_REFLECTIONS
|
#if USE_REFLECTIONS
|
||||||
float3 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb;
|
float4 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness);
|
||||||
|
reflections.rgb *= reflections.a;
|
||||||
|
|
||||||
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
||||||
// Screen Space Reflections
|
// Screen Space Reflections
|
||||||
@@ -116,7 +121,7 @@ void PS_Forward(
|
|||||||
Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR;
|
Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR;
|
||||||
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
||||||
float stepSize = ScreenSize.z; // 1 / screenWidth
|
float stepSize = ScreenSize.z; // 1 / screenWidth
|
||||||
float maxSamples = 48;
|
float maxSamples = 50;
|
||||||
float worldAntiSelfOcclusionBias = 0.1f;
|
float worldAntiSelfOcclusionBias = 0.1f;
|
||||||
float brdfBias = 0.82f;
|
float brdfBias = 0.82f;
|
||||||
float drawDistance = 5000.0f;
|
float drawDistance = 5000.0f;
|
||||||
@@ -124,7 +129,7 @@ void PS_Forward(
|
|||||||
if (hit.z > 0)
|
if (hit.z > 0)
|
||||||
{
|
{
|
||||||
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
|
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
|
||||||
reflections = lerp(reflections, screenColor, hit.z);
|
reflections.rgb = lerp(reflections.rgb, screenColor, hit.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to software tracing if possible
|
// Fallback to software tracing if possible
|
||||||
@@ -136,17 +141,17 @@ void PS_Forward(
|
|||||||
if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas))
|
if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas))
|
||||||
{
|
{
|
||||||
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
|
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
|
||||||
reflections = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
|
reflections.rgb = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
light.rgb += reflections * GetReflectionSpecularLighting(ViewPos, gBuffer) * light.a;
|
light.rgb += reflections.rgb * GetReflectionSpecularLighting(PreIntegratedGF, ViewPos, gBuffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Add lighting (apply ambient occlusion)
|
// Add lighting
|
||||||
output.rgb += light.rgb * gBuffer.AO;
|
output.rgb += light.rgb;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -158,17 +163,13 @@ void PS_Forward(
|
|||||||
#else
|
#else
|
||||||
float fogSceneDistance = gBuffer.ViewPos.z;
|
float fogSceneDistance = gBuffer.ViewPos.z;
|
||||||
#endif
|
#endif
|
||||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance);
|
float fogSkipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||||
|
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, fogSkipDistance, fogSceneDistance);
|
||||||
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
|
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
|
||||||
{
|
{
|
||||||
// Sample volumetric fog and mix it in
|
// Sample volumetric fog and mix it in
|
||||||
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
||||||
float3 viewVector = materialInput.WorldPosition - ViewPos;
|
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, VolumetricFog, materialInput.WorldPosition - ViewPos, screenUV, TemporalAAJitter);
|
||||||
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);
|
fog = CombineVolumetricFog(fog, volumetricFog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ struct VertexOutput
|
|||||||
#endif
|
#endif
|
||||||
float4 ClipExtents : TEXCOORD3;
|
float4 ClipExtents : TEXCOORD3;
|
||||||
float2 ClipOrigin : TEXCOORD4;
|
float2 ClipOrigin : TEXCOORD4;
|
||||||
|
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
|
||||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||||
#endif
|
#endif
|
||||||
@@ -55,6 +56,7 @@ struct PixelInput
|
|||||||
#endif
|
#endif
|
||||||
float4 ClipExtents : TEXCOORD3;
|
float4 ClipExtents : TEXCOORD3;
|
||||||
float2 ClipOrigin : TEXCOORD4;
|
float2 ClipOrigin : TEXCOORD4;
|
||||||
|
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
|
||||||
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
#if USE_CUSTOM_VERTEX_INTERPOLATORS
|
||||||
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
|
||||||
#endif
|
#endif
|
||||||
@@ -67,6 +69,7 @@ struct MaterialInput
|
|||||||
float3 WorldPosition;
|
float3 WorldPosition;
|
||||||
float TwoSidedSign;
|
float TwoSidedSign;
|
||||||
float2 TexCoord;
|
float2 TexCoord;
|
||||||
|
float2 CustomData; // x-per-geometry type, y-features mask
|
||||||
#if USE_VERTEX_COLOR
|
#if USE_VERTEX_COLOR
|
||||||
half4 VertexColor;
|
half4 VertexColor;
|
||||||
#endif
|
#endif
|
||||||
@@ -84,6 +87,7 @@ MaterialInput GetMaterialInput(Render2DVertex input, VertexOutput output)
|
|||||||
MaterialInput result;
|
MaterialInput result;
|
||||||
result.WorldPosition = output.WorldPosition;
|
result.WorldPosition = output.WorldPosition;
|
||||||
result.TexCoord = output.TexCoord;
|
result.TexCoord = output.TexCoord;
|
||||||
|
result.CustomData = input.CustomDataAndClipOrigin.xy;
|
||||||
#if USE_VERTEX_COLOR
|
#if USE_VERTEX_COLOR
|
||||||
result.VertexColor = output.VertexColor;
|
result.VertexColor = output.VertexColor;
|
||||||
#endif
|
#endif
|
||||||
@@ -103,6 +107,7 @@ MaterialInput GetMaterialInput(PixelInput input)
|
|||||||
MaterialInput result;
|
MaterialInput result;
|
||||||
result.WorldPosition = input.WorldPosition;
|
result.WorldPosition = input.WorldPosition;
|
||||||
result.TexCoord = input.TexCoord;
|
result.TexCoord = input.TexCoord;
|
||||||
|
result.CustomData = input.CustomData;
|
||||||
#if USE_VERTEX_COLOR
|
#if USE_VERTEX_COLOR
|
||||||
result.VertexColor = input.VertexColor;
|
result.VertexColor = input.VertexColor;
|
||||||
#endif
|
#endif
|
||||||
@@ -229,6 +234,7 @@ VertexOutput VS_GUI(Render2DVertex input)
|
|||||||
#if USE_VERTEX_COLOR
|
#if USE_VERTEX_COLOR
|
||||||
output.VertexColor = input.Color;
|
output.VertexColor = input.Color;
|
||||||
#endif
|
#endif
|
||||||
|
output.CustomData = input.CustomDataAndClipOrigin.xy;
|
||||||
output.ClipOrigin = input.CustomDataAndClipOrigin.zw;
|
output.ClipOrigin = input.CustomDataAndClipOrigin.zw;
|
||||||
output.ClipExtents = input.ClipExtents;
|
output.ClipExtents = input.ClipExtents;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "./Flax/Common.hlsl"
|
#include "./Flax/Common.hlsl"
|
||||||
#include "./Flax/MaterialCommon.hlsl"
|
#include "./Flax/MaterialCommon.hlsl"
|
||||||
#include "./Flax/GBufferCommon.hlsl"
|
#include "./Flax/GBufferCommon.hlsl"
|
||||||
|
#include "./Flax/VolumetricFog.hlsl"
|
||||||
@7
|
@7
|
||||||
|
|
||||||
// Primary constant buffer (with additional material parameters)
|
// Primary constant buffer (with additional material parameters)
|
||||||
@@ -21,6 +22,7 @@ float Dummy0;
|
|||||||
float VolumetricFogMaxDistance;
|
float VolumetricFogMaxDistance;
|
||||||
int ParticleStride;
|
int ParticleStride;
|
||||||
int ParticleIndex;
|
int ParticleIndex;
|
||||||
|
float4 GridSliceParameters;
|
||||||
@1META_CB_END
|
@1META_CB_END
|
||||||
|
|
||||||
// Particles attributes buffer
|
// Particles attributes buffer
|
||||||
@@ -202,19 +204,19 @@ Material GetMaterialPS(MaterialInput input)
|
|||||||
META_PS(true, FEATURE_LEVEL_SM5)
|
META_PS(true, FEATURE_LEVEL_SM5)
|
||||||
void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out float4 VBufferB : SV_Target1)
|
void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out float4 VBufferB : SV_Target1)
|
||||||
{
|
{
|
||||||
|
// Reproject grid position back to the screen and world space
|
||||||
uint3 gridCoordinate = uint3(input.Vertex.Position.xy, input.LayerIndex);
|
uint3 gridCoordinate = uint3(input.Vertex.Position.xy, input.LayerIndex);
|
||||||
float3 cellOffset = 0.5f;
|
float3 cellOffset = 0.5f;
|
||||||
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
||||||
float zSlice = gridCoordinate.z + cellOffset.z;
|
float sceneDepth = GetDepthFromSlice(GridSliceParameters, gridCoordinate.z + cellOffset.z) / ViewFar;
|
||||||
float sceneDepth = (zSlice / GridSize.z) * VolumetricFogMaxDistance / ViewFar;
|
|
||||||
float deviceDepth = (ViewInfo.w / sceneDepth) + ViewInfo.z;
|
float deviceDepth = (ViewInfo.w / sceneDepth) + ViewInfo.z;
|
||||||
float4 clipPos = float4(volumeUV * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0);
|
float4 clipPos = float4(volumeUV * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0);
|
||||||
float4 wsPos = mul(clipPos, InverseViewProjectionMatrix);
|
float4 wsPos = mul(clipPos, InverseViewProjectionMatrix);
|
||||||
float3 positionWS = wsPos.xyz / wsPos.w;
|
wsPos.xyz /= wsPos.w;
|
||||||
|
|
||||||
// Get material parameters
|
// Get material parameters
|
||||||
MaterialInput materialInput = (MaterialInput)0;
|
MaterialInput materialInput = (MaterialInput)0;
|
||||||
materialInput.WorldPosition = positionWS;
|
materialInput.WorldPosition = wsPos.xyz;
|
||||||
materialInput.TexCoord = input.Vertex.TexCoord;
|
materialInput.TexCoord = input.Vertex.TexCoord;
|
||||||
materialInput.ParticleIndex = ParticleIndex;
|
materialInput.ParticleIndex = ParticleIndex;
|
||||||
materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
|
materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
|
||||||
@@ -225,9 +227,10 @@ void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out fl
|
|||||||
Material material = GetMaterialPS(materialInput);
|
Material material = GetMaterialPS(materialInput);
|
||||||
|
|
||||||
// Compute fog properties
|
// Compute fog properties
|
||||||
|
material.Opacity *= material.Mask;
|
||||||
float3 albedo = material.Color;
|
float3 albedo = material.Color;
|
||||||
float extinction = material.Opacity * material.Mask * 0.001f;
|
float extinction = material.Opacity * 0.001f;
|
||||||
float3 emission = material.Emissive;
|
float3 emission = material.Emissive * material.Opacity;
|
||||||
float3 scattering = albedo * extinction;
|
float3 scattering = albedo * extinction;
|
||||||
float absorption = max(0.0f, extinction - Luminance(scattering));
|
float absorption = max(0.0f, extinction - Luminance(scattering));
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/Fog.flax
LFS
BIN
Content/Shaders/Fog.flax
LFS
Binary file not shown.
BIN
Content/Shaders/GI/DDGI.flax
LFS
BIN
Content/Shaders/GI/DDGI.flax
LFS
Binary file not shown.
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0f34bf867df5f4296ca66ac691c2bca4efa168fb9e21ca4e613e8086669575cf
|
oid sha256:615dff65b01507be6c4de722e126324aba20fc197f8e12dafaa94a05e46cba6e
|
||||||
size 13296
|
size 13222
|
||||||
|
|||||||
BIN
Content/Shaders/GUI.flax
LFS
BIN
Content/Shaders/GUI.flax
LFS
Binary file not shown.
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:064f54786958f109222c49cbc0358ff4f345b30010fcd5e8cc1fab7bdc68c4fe
|
oid sha256:1f07ebb16820897e8598ae7a0627cb75b3d28e9dceea3ad4bd9ff543d5cdd01c
|
||||||
size 13349
|
size 13979
|
||||||
|
|||||||
BIN
Content/Shaders/Histogram.flax
LFS
BIN
Content/Shaders/Histogram.flax
LFS
Binary file not shown.
BIN
Content/Shaders/Lights.flax
LFS
BIN
Content/Shaders/Lights.flax
LFS
Binary file not shown.
BIN
Content/Shaders/MultiScaler.flax
LFS
BIN
Content/Shaders/MultiScaler.flax
LFS
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/Reflections.flax
LFS
BIN
Content/Shaders/Reflections.flax
LFS
Binary file not shown.
BIN
Content/Shaders/SSAO.flax
LFS
BIN
Content/Shaders/SSAO.flax
LFS
Binary file not shown.
BIN
Content/Shaders/SSR.flax
LFS
BIN
Content/Shaders/SSR.flax
LFS
Binary file not shown.
BIN
Content/Shaders/Sky.flax
LFS
BIN
Content/Shaders/Sky.flax
LFS
Binary file not shown.
BIN
Content/Shaders/TAA.flax
LFS
BIN
Content/Shaders/TAA.flax
LFS
Binary file not shown.
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:872ac3560279bfd0aeb989ebac1b49750dd142b985bc40058888dfd2b63fe9b2
|
oid sha256:706adde844360c2b0e65ecabaf1d2e2cc4eb4ac7ca9d483d0dd04ec8163b3d97
|
||||||
size 13214
|
size 13081
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
"Name": "Flax",
|
"Name": "Flax",
|
||||||
"Version": {
|
"Version": {
|
||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 11,
|
"Minor": 12,
|
||||||
"Revision": 0,
|
"Revision": 0,
|
||||||
"Build": 6805
|
"Build": 6905
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
|
||||||
"GameTarget": "FlaxGame",
|
"GameTarget": "FlaxGame",
|
||||||
"EditorTarget": "FlaxEditor",
|
"EditorTarget": "FlaxEditor",
|
||||||
"Configuration": {
|
"Configuration": {
|
||||||
|
|||||||
@@ -188,7 +188,7 @@
|
|||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_CASE_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
|
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||||
|
|||||||
@@ -187,6 +187,11 @@ namespace FlaxEditor.Content.Import
|
|||||||
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
|
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
|
||||||
_settings.Settings.Type = TextureFormatType.GrayScale;
|
_settings.Settings.Type = TextureFormatType.GrayScale;
|
||||||
}
|
}
|
||||||
|
else if (_settings.Settings.Type == TextureFormatType.ColorRGB)
|
||||||
|
{
|
||||||
|
// Blind guess that common color texture is sRGB
|
||||||
|
_settings.Settings.sRGB = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to restore target asset texture import options (useful for fast reimport)
|
// Try to restore target asset texture import options (useful for fast reimport)
|
||||||
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
||||||
|
|||||||
@@ -141,6 +141,11 @@ API_ENUM() enum class BuildPlatform
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_ENUM(Attributes="EditorDisplay(null, \"Windows ARM64\")")
|
API_ENUM(Attributes="EditorDisplay(null, \"Windows ARM64\")")
|
||||||
WindowsARM64 = 15,
|
WindowsARM64 = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Web
|
||||||
|
/// </summary>
|
||||||
|
Web = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -188,6 +193,11 @@ enum class DotNetAOTModes
|
|||||||
/// Use Mono AOT to cross-compile all used C# assemblies into native platform static libraries which can be linked into a single shared library.
|
/// Use Mono AOT to cross-compile all used C# assemblies into native platform static libraries which can be linked into a single shared library.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MonoAOTStatic,
|
MonoAOTStatic,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target platform doesn't support .NET or it has been disabled.
|
||||||
|
/// </summary>
|
||||||
|
NoDotnet,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||||
|
|||||||
@@ -69,6 +69,10 @@
|
|||||||
#include "Platform/iOS/iOSPlatformTools.h"
|
#include "Platform/iOS/iOSPlatformTools.h"
|
||||||
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if PLATFORM_TOOLS_WEB
|
||||||
|
#include "Platform/Web/WebPlatformTools.h"
|
||||||
|
#include "Engine/Platform/Web/WebPlatformSettings.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace GameCookerImpl
|
namespace GameCookerImpl
|
||||||
{
|
{
|
||||||
@@ -151,6 +155,8 @@ const Char* ToString(const BuildPlatform platform)
|
|||||||
return TEXT("iOS ARM64");
|
return TEXT("iOS ARM64");
|
||||||
case BuildPlatform::WindowsARM64:
|
case BuildPlatform::WindowsARM64:
|
||||||
return TEXT("Windows ARM64");
|
return TEXT("Windows ARM64");
|
||||||
|
case BuildPlatform::Web:
|
||||||
|
return TEXT("Web");
|
||||||
default:
|
default:
|
||||||
return TEXT("");
|
return TEXT("");
|
||||||
}
|
}
|
||||||
@@ -183,6 +189,8 @@ const Char* ToString(const DotNetAOTModes mode)
|
|||||||
return TEXT("MonoAOTDynamic");
|
return TEXT("MonoAOTDynamic");
|
||||||
case DotNetAOTModes::MonoAOTStatic:
|
case DotNetAOTModes::MonoAOTStatic:
|
||||||
return TEXT("MonoAOTStatic");
|
return TEXT("MonoAOTStatic");
|
||||||
|
case DotNetAOTModes::NoDotnet:
|
||||||
|
return TEXT("NoDotnet");
|
||||||
default:
|
default:
|
||||||
return TEXT("");
|
return TEXT("");
|
||||||
}
|
}
|
||||||
@@ -307,6 +315,10 @@ void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& archi
|
|||||||
platform = TEXT("Windows");
|
platform = TEXT("Windows");
|
||||||
architecture = TEXT("ARM64");
|
architecture = TEXT("ARM64");
|
||||||
break;
|
break;
|
||||||
|
case BuildPlatform::Web:
|
||||||
|
platform = TEXT("Web");
|
||||||
|
architecture = TEXT("x86");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(Fatal, "Unknown or unsupported build platform.");
|
LOG(Fatal, "Unknown or unsupported build platform.");
|
||||||
}
|
}
|
||||||
@@ -461,6 +473,11 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
|||||||
case BuildPlatform::iOSARM64:
|
case BuildPlatform::iOSARM64:
|
||||||
result = New<iOSPlatformTools>();
|
result = New<iOSPlatformTools>();
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#if PLATFORM_TOOLS_WEB
|
||||||
|
case BuildPlatform::Web:
|
||||||
|
result = New<WebPlatformTools>();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
Tools.Add(platform, result);
|
Tools.Add(platform, result);
|
||||||
@@ -604,6 +621,9 @@ void GameCooker::GetCurrentPlatform(PlatformType& platform, BuildPlatform& build
|
|||||||
case PlatformType::iOS:
|
case PlatformType::iOS:
|
||||||
buildPlatform = BuildPlatform::iOSARM64;
|
buildPlatform = BuildPlatform::iOSARM64;
|
||||||
break;
|
break;
|
||||||
|
case PlatformType::Web:
|
||||||
|
buildPlatform = BuildPlatform::Web;
|
||||||
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ namespace FlaxEditor
|
|||||||
case BuildPlatform.MacOSARM64:
|
case BuildPlatform.MacOSARM64:
|
||||||
case BuildPlatform.MacOSx64: return PlatformType.Mac;
|
case BuildPlatform.MacOSx64: return PlatformType.Mac;
|
||||||
case BuildPlatform.iOSARM64: return PlatformType.iOS;
|
case BuildPlatform.iOSARM64: return PlatformType.iOS;
|
||||||
|
case BuildPlatform.Web: return PlatformType.Web;
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(buildPlatform), buildPlatform, null);
|
default: throw new ArgumentOutOfRangeException(nameof(buildPlatform), buildPlatform, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ Array<byte> AndroidPlatformTools::SaveCache(CookingData& data, IBuildCache* cach
|
|||||||
result.Add((const byte*)&platformCache, sizeof(platformCache));
|
result.Add((const byte*)&platformCache, sizeof(platformCache));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidPlatformTools::OnBuildStarted(CookingData& data)
|
void AndroidPlatformTools::OnBuildStarted(CookingData& data)
|
||||||
{
|
{
|
||||||
// Adjust the cooking output folder to be located inside the Gradle assets directory
|
// Adjust the cooking output folder to be located inside the Gradle assets directory
|
||||||
@@ -412,7 +413,6 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
}
|
}
|
||||||
LOG(Info, "Output Android APK application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
LOG(Info, "Output Android APK application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
157
Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp
Normal file
157
Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#if PLATFORM_TOOLS_WEB
|
||||||
|
|
||||||
|
#include "WebPlatformTools.h"
|
||||||
|
#include "Engine/Platform/File.h"
|
||||||
|
#include "Engine/Platform/FileSystem.h"
|
||||||
|
#include "Engine/Platform/CreateProcessSettings.h"
|
||||||
|
#include "Engine/Platform/Web/WebPlatformSettings.h"
|
||||||
|
#include "Engine/Core/Config/GameSettings.h"
|
||||||
|
#include "Engine/Core/Config/BuildSettings.h"
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Content/JsonAsset.h"
|
||||||
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||||
|
#include "Editor/Cooker/GameCooker.h"
|
||||||
|
|
||||||
|
IMPLEMENT_SETTINGS_GETTER(WebPlatformSettings, WebPlatform);
|
||||||
|
|
||||||
|
const Char* WebPlatformTools::GetDisplayName() const
|
||||||
|
{
|
||||||
|
return TEXT("Web");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Char* WebPlatformTools::GetName() const
|
||||||
|
{
|
||||||
|
return TEXT("Web");
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformType WebPlatformTools::GetPlatform() const
|
||||||
|
{
|
||||||
|
return PlatformType::Web;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchitectureType WebPlatformTools::GetArchitecture() const
|
||||||
|
{
|
||||||
|
return ArchitectureType::x86;
|
||||||
|
}
|
||||||
|
|
||||||
|
DotNetAOTModes WebPlatformTools::UseAOT() const
|
||||||
|
{
|
||||||
|
return DotNetAOTModes::NoDotnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
|
||||||
|
{
|
||||||
|
// TODO: texture compression for Web (eg. ASTC for mobile and BC for others?)
|
||||||
|
return PixelFormatExtensions::FindUncompressedFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebPlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||||
|
{
|
||||||
|
String extension = FileSystem::GetExtension(file);
|
||||||
|
return extension.IsEmpty() || extension == TEXT("html") || extension == TEXT("js") || extension == TEXT("wasm");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPlatformTools::OnBuildStarted(CookingData& data)
|
||||||
|
{
|
||||||
|
// Adjust the cooking output folder for the data files so file_packager tool can build the and output final data inside the cooker output folder
|
||||||
|
data.DataOutputPath = data.CacheDirectory / TEXT("Files");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebPlatformTools::OnPostProcess(CookingData& data)
|
||||||
|
{
|
||||||
|
const auto gameSettings = GameSettings::Get();
|
||||||
|
const auto platformSettings = WebPlatformSettings::Get();
|
||||||
|
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||||
|
|
||||||
|
// Get name of the output binary (JavaScript and WebAssembly files match)
|
||||||
|
String gameJs;
|
||||||
|
{
|
||||||
|
Array<String> files;
|
||||||
|
FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*"), DirectorySearchOption::TopDirectoryOnly);
|
||||||
|
for (String& file : files)
|
||||||
|
{
|
||||||
|
if (file.EndsWith(TEXT(".js")))
|
||||||
|
{
|
||||||
|
String outputWasm = String(StringUtils::GetPathWithoutExtension(file)) + TEXT(".wasm");
|
||||||
|
if (files.Contains(outputWasm))
|
||||||
|
{
|
||||||
|
gameJs = file;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gameJs.IsEmpty())
|
||||||
|
{
|
||||||
|
data.Error(TEXT("Failed to find the main JavaScript for the output game"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack data files into a single file using Emscripten's file_packager tool
|
||||||
|
{
|
||||||
|
CreateProcessSettings procSettings;
|
||||||
|
String emscriptenSdk = TEXT("EMSDK");
|
||||||
|
Platform::GetEnvironmentVariable(emscriptenSdk, emscriptenSdk);
|
||||||
|
procSettings.FileName = emscriptenSdk / TEXT("upstream/emscripten/tools/file_packager");
|
||||||
|
#if PLATFORM_WIN32
|
||||||
|
procSettings.FileName += TEXT(".bat");
|
||||||
|
#endif
|
||||||
|
procSettings.Arguments = String::Format(TEXT("files.data --preload \"{}@/\" --lz4 --js-output=files.js"), data.DataOutputPath);
|
||||||
|
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||||
|
const int32 result = Platform::CreateProcess(procSettings);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
if (!FileSystem::FileExists(procSettings.FileName))
|
||||||
|
data.Error(TEXT("Missing file_packager.bat. Ensure Emscripten SDK installation is valid and 'EMSDK' environment variable points to it."));
|
||||||
|
data.Error(String::Format(TEXT("Failed to package project files (result code: {0}). See log for more info."), result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: customizable HTML templates
|
||||||
|
|
||||||
|
// Insert packaged file system with game data
|
||||||
|
{
|
||||||
|
String gameJsText;
|
||||||
|
if (File::ReadAllText(gameJs, gameJsText))
|
||||||
|
{
|
||||||
|
data.Error(String::Format(TEXT("Failed to load file '{}'"), gameJs));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const String filesIncludeBegin = TEXT("// include: files.js");
|
||||||
|
const String filesIncludeEnd = TEXT("// end include: files.js");
|
||||||
|
if (!gameJsText.Contains(filesIncludeBegin))
|
||||||
|
{
|
||||||
|
// Insert generated files.js into the main game file after the minimum_runtime_check.js include
|
||||||
|
String fileJsText;
|
||||||
|
String fileJs = data.OriginalOutputPath / TEXT("files.js");
|
||||||
|
if (File::ReadAllText(fileJs, fileJsText))
|
||||||
|
{
|
||||||
|
data.Error(String::Format(TEXT("Failed to load file '{}'"), fileJs));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const String insertPrefixLocation = TEXT("// end include: minimum_runtime_check.js");
|
||||||
|
int32 location = gameJsText.Find(insertPrefixLocation);
|
||||||
|
CHECK_RETURN(location != -1, true);
|
||||||
|
location += insertPrefixLocation.Length() + 1;
|
||||||
|
fileJsText = filesIncludeBegin + TEXT("\n") + fileJsText + TEXT("\n") + filesIncludeEnd + TEXT("\n");
|
||||||
|
gameJsText.Insert(location, fileJsText);
|
||||||
|
File::WriteAllText(gameJs, gameJsText, Encoding::UTF8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto buildSettings = BuildSettings::Get();
|
||||||
|
if (buildSettings->SkipPackaging)
|
||||||
|
return false;
|
||||||
|
GameCooker::PackageFiles();
|
||||||
|
|
||||||
|
// TODO: minify/compress output JS files (in Release builds)
|
||||||
|
|
||||||
|
LOG(Info, "Output website size: {0} MB", FileSystem::GetDirectorySize(data.OriginalOutputPath) / 1024 / 1024);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
27
Source/Editor/Cooker/Platform/Web/WebPlatformTools.h
Normal file
27
Source/Editor/Cooker/Platform/Web/WebPlatformTools.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if PLATFORM_TOOLS_WEB
|
||||||
|
|
||||||
|
#include "../../PlatformTools.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Web platform support tools.
|
||||||
|
/// </summary>
|
||||||
|
class WebPlatformTools : public PlatformTools
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// [PlatformTools]
|
||||||
|
const Char* GetDisplayName() const override;
|
||||||
|
const Char* GetName() const override;
|
||||||
|
PlatformType GetPlatform() const override;
|
||||||
|
ArchitectureType GetArchitecture() const override;
|
||||||
|
DotNetAOTModes UseAOT() const override;
|
||||||
|
PixelFormat GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) override;
|
||||||
|
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||||
|
void OnBuildStarted(CookingData& data) override;
|
||||||
|
bool OnPostProcess(CookingData& data) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -572,6 +572,14 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
|||||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if PLATFORM_TOOLS_WEB
|
||||||
|
case BuildPlatform::Web:
|
||||||
|
{
|
||||||
|
const char* platformDefineName = "PLATFORM_WEB";
|
||||||
|
// TODO: compile shaders for WebGPU
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,17 +39,23 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
}
|
}
|
||||||
String dstDotnet = data.DataOutputPath / TEXT("Dotnet");
|
String dstDotnet = data.DataOutputPath / TEXT("Dotnet");
|
||||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||||
const bool usAOT = aotMode != DotNetAOTModes::None;
|
const bool usAOT = aotMode != DotNetAOTModes::None && aotMode != DotNetAOTModes::NoDotnet;
|
||||||
if (usAOT)
|
if (usAOT)
|
||||||
{
|
{
|
||||||
// Deploy Dotnet files into intermediate cooking directory for AOT
|
// Deploy Dotnet files into intermediate cooking directory for AOT
|
||||||
FileSystem::DeleteDirectory(dstDotnet);
|
FileSystem::DeleteDirectory(dstDotnet);
|
||||||
dstDotnet = data.ManagedCodeOutputPath;
|
dstDotnet = data.ManagedCodeOutputPath;
|
||||||
}
|
}
|
||||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
if (aotMode == DotNetAOTModes::NoDotnet)
|
||||||
|
{
|
||||||
|
// No .NET
|
||||||
|
FileSystem::DeleteDirectory(dstDotnet);
|
||||||
|
}
|
||||||
|
else if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||||
{
|
{
|
||||||
// Use system-installed .NET Runtime
|
// Use system-installed .NET Runtime
|
||||||
FileSystem::DeleteDirectory(dstDotnet);
|
FileSystem::DeleteDirectory(dstDotnet);
|
||||||
|
LOG(Info, "Not using .NET Runtime");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||||
{
|
{
|
||||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||||
if (aotMode == DotNetAOTModes::None || EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
if (aotMode == DotNetAOTModes::None ||
|
||||||
|
aotMode == DotNetAOTModes::NoDotnet ||
|
||||||
|
EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||||
return;
|
return;
|
||||||
const auto& buildSettings = *BuildSettings::Get();
|
const auto& buildSettings = *BuildSettings::Get();
|
||||||
|
|
||||||
@@ -49,7 +51,8 @@ void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
|||||||
bool PrecompileAssembliesStep::Perform(CookingData& data)
|
bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||||
{
|
{
|
||||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||||
if (aotMode == DotNetAOTModes::None)
|
if (aotMode == DotNetAOTModes::None ||
|
||||||
|
aotMode == DotNetAOTModes::NoDotnet)
|
||||||
return false;
|
return false;
|
||||||
const auto& buildSettings = *BuildSettings::Get();
|
const auto& buildSettings = *BuildSettings::Get();
|
||||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
|
|
||||||
if (Values.HasDifferentTypes == false)
|
if (Values.HasDifferentTypes == false)
|
||||||
{
|
{
|
||||||
var group = layout.Group("Bake");
|
var group = layout.Group("Probe");
|
||||||
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||||
_bake = group.Button("Bake").Button;
|
_bake = group.Button("Bake").Button;
|
||||||
_bake.Clicked += BakeButtonClicked;
|
_bake.Clicked += BakeButtonClicked;
|
||||||
|
var view = group.Button("View", "Opens the probe texture viewer");
|
||||||
|
view.Button.Clicked += OnViewButtonClicked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,5 +52,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnViewButtonClicked()
|
||||||
|
{
|
||||||
|
foreach (var value in Values)
|
||||||
|
{
|
||||||
|
if (value is EnvironmentProbe probe && probe.ProbeAsset)
|
||||||
|
Editor.Instance.ContentEditing.Open(probe.ProbeAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
filesCount += files.Length;
|
filesCount += files.Length;
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
FindNewKeysCpp(file, newKeys, allKeys);
|
FindNewKeysCpp(file, newKeys, allKeys);
|
||||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.hpp", SearchOption.AllDirectories)).ToArray();;
|
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.hpp", SearchOption.AllDirectories)).ToArray();
|
||||||
filesCount += files.Length;
|
filesCount += files.Length;
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
FindNewKeysCpp(file, newKeys, allKeys);
|
FindNewKeysCpp(file, newKeys, allKeys);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEngine;
|
||||||
|
|
||||||
|
namespace FlaxEditor.CustomEditors.Dedicated
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Custom editor for <see cref="NavMeshBoundsVolume"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ActorEditor" />
|
||||||
|
[CustomEditor(typeof(NavMeshBoundsVolume)), DefaultEditor]
|
||||||
|
internal class NavMeshBoundsVolumeEditor : ActorEditor
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
|
{
|
||||||
|
base.Initialize(layout);
|
||||||
|
|
||||||
|
if (Values.HasDifferentTypes == false)
|
||||||
|
{
|
||||||
|
var button = layout.Button("Build");
|
||||||
|
button.Button.Clicked += OnBuildClicked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBuildClicked()
|
||||||
|
{
|
||||||
|
foreach (var value in Values)
|
||||||
|
{
|
||||||
|
if (value is NavMeshBoundsVolume volume)
|
||||||
|
{
|
||||||
|
Navigation.BuildNavMesh(volume.Box, volume.Scene);
|
||||||
|
Editor.Instance.Scene.MarkSceneEdited(volume.Scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
|
||||||
using FlaxEditor.CustomEditors.GUI;
|
using FlaxEditor.CustomEditors.GUI;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|||||||
@@ -909,7 +909,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
settingsButton.Tag = script;
|
settingsButton.Tag = script;
|
||||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||||
|
|
||||||
group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
|
// Adjust margin to not overlap with other ui elements in the header
|
||||||
|
group.Panel.HeaderTextMargin = group.Panel.HeaderTextMargin with { Left = scriptDrag.Right - 12, Right = settingsButton.Width + Utilities.Constants.UIMargin };
|
||||||
group.Object(values, editor);
|
group.Object(values, editor);
|
||||||
// Remove drop down arrows and containment lines if no objects in the group
|
// Remove drop down arrows and containment lines if no objects in the group
|
||||||
if (group.Children.Count == 0)
|
if (group.Children.Count == 0)
|
||||||
|
|||||||
@@ -450,6 +450,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
protected bool NotNullItems;
|
protected bool NotNullItems;
|
||||||
|
|
||||||
private IntValueBox _sizeBox;
|
private IntValueBox _sizeBox;
|
||||||
|
private Label _label;
|
||||||
private Color _background;
|
private Color _background;
|
||||||
private int _elementsCount, _minCount, _maxCount;
|
private int _elementsCount, _minCount, _maxCount;
|
||||||
private bool _readOnly;
|
private bool _readOnly;
|
||||||
@@ -566,7 +567,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Parent = dropPanel,
|
Parent = dropPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
var label = new Label
|
_label = new Label
|
||||||
{
|
{
|
||||||
Text = "Size",
|
Text = "Size",
|
||||||
AnchorPreset = AnchorPresets.TopRight,
|
AnchorPreset = AnchorPresets.TopRight,
|
||||||
@@ -592,11 +593,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
panel.Panel.Offsets = new Margin(7, 7, 0, 0);
|
panel.Panel.Offsets = new Margin(7, 7, 0, 0);
|
||||||
panel.Panel.BackgroundColor = _background;
|
panel.Panel.BackgroundColor = _background;
|
||||||
var elementType = ElementType;
|
var elementType = ElementType;
|
||||||
|
var bindingAttr = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public;
|
||||||
bool single = elementType.IsPrimitive ||
|
bool single = elementType.IsPrimitive ||
|
||||||
elementType.Equals(new ScriptType(typeof(string))) ||
|
elementType.Equals(new ScriptType(typeof(string))) ||
|
||||||
elementType.IsEnum ||
|
elementType.IsEnum ||
|
||||||
(elementType.GetFields().Length == 1 && elementType.GetProperties().Length == 0) ||
|
(elementType.GetFields(bindingAttr).Length == 1 && elementType.GetProperties(bindingAttr).Length == 0) ||
|
||||||
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
|
(elementType.GetProperties(bindingAttr).Length == 1 && elementType.GetFields(bindingAttr).Length == 0) ||
|
||||||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
||||||
elementType.Equals(new ScriptType(typeof(SettingsBase)));
|
elementType.Equals(new ScriptType(typeof(SettingsBase)));
|
||||||
if (_cachedDropPanels == null)
|
if (_cachedDropPanels == null)
|
||||||
@@ -672,6 +674,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Resize(Count + 1);
|
Resize(Count + 1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Layout.ContainerControl.SizeChanged += OnLayoutSizeChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSetupContextMenu(ContextMenu menu, DropPanel panel)
|
private void OnSetupContextMenu(ContextMenu menu, DropPanel panel)
|
||||||
@@ -696,10 +700,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnLayoutSizeChanged(Control control)
|
||||||
|
{
|
||||||
|
if (Layout.ContainerControl is DropPanel dropPanel)
|
||||||
|
{
|
||||||
|
// Hide "Size" text when array editor title overlaps
|
||||||
|
var headerTextSize = dropPanel.HeaderTextFont.GetFont().MeasureText(dropPanel.HeaderText);
|
||||||
|
if (headerTextSize.X + DropPanel.DropDownIconSize >= _label.Left)
|
||||||
|
_label.TextColor = _label.TextColorHighlighted = Color.Transparent;
|
||||||
|
else
|
||||||
|
_label.TextColor = _label.TextColorHighlighted = FlaxEngine.GUI.Style.Current.Foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Deinitialize()
|
protected override void Deinitialize()
|
||||||
{
|
{
|
||||||
_sizeBox = null;
|
_sizeBox = null;
|
||||||
|
Layout.ContainerControl.SizeChanged -= OnLayoutSizeChanged;
|
||||||
|
|
||||||
base.Deinitialize();
|
base.Deinitialize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return inputEvent;
|
return inputEvent;
|
||||||
if (Values[0] is string str)
|
if (Values[0] is string str)
|
||||||
return str;
|
return str;
|
||||||
|
if (Values.Type.Type == typeof(InputEvent))
|
||||||
|
return new InputEvent();
|
||||||
if (Values.Type.Type == typeof(string))
|
if (Values.Type.Type == typeof(string))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ namespace FlaxEditor.CustomEditors.Elements
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var settingsButtonSize = Panel.HeaderHeight;
|
var settingsButtonSize = Panel.HeaderHeight;
|
||||||
return new Image
|
Panel.HeaderTextMargin = Panel.HeaderTextMargin with { Right = settingsButtonSize + Utilities.Constants.UIMargin };
|
||||||
|
; return new Image
|
||||||
{
|
{
|
||||||
TooltipText = "Settings",
|
TooltipText = "Settings",
|
||||||
AutoFocus = true,
|
AutoFocus = true,
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ public class Editor : EditorModule
|
|||||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
|
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
|
||||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "iOS", "PLATFORM_TOOLS_IOS");
|
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "iOS", "PLATFORM_TOOLS_IOS");
|
||||||
}
|
}
|
||||||
|
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Web", "PLATFORM_TOOLS_WEB");
|
||||||
|
|
||||||
// Visual Studio integration
|
// Visual Studio integration
|
||||||
if (options.Platform.Target == TargetPlatform.Windows && Flax.Build.Platform.BuildTargetPlatform == TargetPlatform.Windows)
|
if (options.Platform.Target == TargetPlatform.Windows && Flax.Build.Platform.BuildTargetPlatform == TargetPlatform.Windows)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ using FlaxEngine.Assertions;
|
|||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Interop;
|
using FlaxEngine.Interop;
|
||||||
using FlaxEngine.Json;
|
using FlaxEngine.Json;
|
||||||
|
using FlaxEngine.Utilities;
|
||||||
|
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
@@ -1370,7 +1371,7 @@ namespace FlaxEditor
|
|||||||
public void BuildCSG()
|
public void BuildCSG()
|
||||||
{
|
{
|
||||||
var scenes = Level.Scenes;
|
var scenes = Level.Scenes;
|
||||||
scenes.ToList().ForEach(x => x.BuildCSG(0));
|
scenes.ForEach(x => x.BuildCSG(0));
|
||||||
Scene.MarkSceneEdited(scenes);
|
Scene.MarkSceneEdited(scenes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +1381,7 @@ namespace FlaxEditor
|
|||||||
public void BuildNavMesh()
|
public void BuildNavMesh()
|
||||||
{
|
{
|
||||||
var scenes = Level.Scenes;
|
var scenes = Level.Scenes;
|
||||||
scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
|
Navigation.BuildNavMesh();
|
||||||
Scene.MarkSceneEdited(scenes);
|
Scene.MarkSceneEdited(scenes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -502,6 +502,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
if (base.OnKeyDown(key))
|
if (base.OnKeyDown(key))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// Keyboard navigation around the menu
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case KeyboardKeys.ArrowDown:
|
case KeyboardKeys.ArrowDown:
|
||||||
@@ -526,6 +527,20 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KeyboardKeys.ArrowRight:
|
||||||
|
for (int i = 0; i < _panel.Children.Count; i++)
|
||||||
|
{
|
||||||
|
if (_panel.Children[i] is ContextMenuChildMenu item && item.Visible && item.IsFocused && !item.ContextMenu.IsOpened)
|
||||||
|
{
|
||||||
|
item.ShowChild(this);
|
||||||
|
item.ContextMenu._panel.Children.FirstOrDefault(x => x is ContextMenuButton && x.Visible)?.Focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyboardKeys.ArrowLeft:
|
||||||
|
ParentCM?.RootWindow.Focus();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasChildCMOpened => _childCM != null;
|
public bool HasChildCMOpened => _childCM != null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parent context menu (if exists).
|
||||||
|
/// </summary>
|
||||||
|
public ContextMenuBase ParentCM => _parentCM;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the topmost context menu.
|
/// Gets the topmost context menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -84,9 +89,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
{
|
{
|
||||||
var cm = this;
|
var cm = this;
|
||||||
while (cm._parentCM != null && cm._isSubMenu)
|
while (cm._parentCM != null && cm._isSubMenu)
|
||||||
{
|
|
||||||
cm = cm._parentCM;
|
cm = cm._parentCM;
|
||||||
}
|
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,6 +114,11 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseInput = true;
|
public bool UseInput = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional flag that can disable UI navigation (tab/enter).
|
||||||
|
/// </summary>
|
||||||
|
public bool UseNavigation = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ContextMenuBase"/> class.
|
/// Initializes a new instance of the <see cref="ContextMenuBase"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -622,6 +630,21 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
case KeyboardKeys.Escape:
|
case KeyboardKeys.Escape:
|
||||||
Hide();
|
Hide();
|
||||||
return true;
|
return true;
|
||||||
|
case KeyboardKeys.Return:
|
||||||
|
if (UseNavigation && Root?.FocusedControl != null)
|
||||||
|
{
|
||||||
|
Root.SubmitFocused();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyboardKeys.Tab:
|
||||||
|
if (UseNavigation && Root != null)
|
||||||
|
{
|
||||||
|
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||||
|
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
CloseMenuOnClick = false;
|
CloseMenuOnClick = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowChild(ContextMenu parentContextMenu)
|
internal void ShowChild(ContextMenu parentContextMenu)
|
||||||
{
|
{
|
||||||
// Hide parent CM popups and set itself as child
|
// Hide parent CM popups and set itself as child
|
||||||
var vAlign = parentContextMenu.ItemsAreaMargin.Top;
|
var vAlign = parentContextMenu.ItemsAreaMargin.Top;
|
||||||
|
|||||||
@@ -522,6 +522,16 @@ namespace FlaxEditor.GUI
|
|||||||
cm.AddButton("Show whole curve", _editor.ShowWholeCurve);
|
cm.AddButton("Show whole curve", _editor.ShowWholeCurve);
|
||||||
cm.AddButton("Reset view", _editor.ResetView);
|
cm.AddButton("Reset view", _editor.ResetView);
|
||||||
}
|
}
|
||||||
|
cm.AddSeparator();
|
||||||
|
var presetCm = cm.AddChildMenu("Apply preset");
|
||||||
|
foreach (var value in Enum.GetValues(typeof(CurvePreset)))
|
||||||
|
{
|
||||||
|
CurvePreset preset = (CurvePreset)value;
|
||||||
|
string name = Utilities.Utils.GetPropertyNameUI(preset.ToString());
|
||||||
|
var b = presetCm.ContextMenu.AddButton(name, () => _editor.ApplyPreset(preset));
|
||||||
|
b.Enabled = !(_editor is LinearCurveEditor<T> && (preset != CurvePreset.Constant && preset != CurvePreset.Linear));
|
||||||
|
}
|
||||||
|
|
||||||
_editor.OnShowContextMenu(cm, selectionCount);
|
_editor.OnShowContextMenu(cm, selectionCount);
|
||||||
cm.Show(this, location);
|
cm.Show(this, location);
|
||||||
}
|
}
|
||||||
@@ -619,6 +629,33 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of avaliable curve presets for the <see cref="CurveEditor{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum CurvePreset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A curve where every point has the same value.
|
||||||
|
/// </summary>
|
||||||
|
Constant,
|
||||||
|
/// <summary>
|
||||||
|
/// A curve linear curve.
|
||||||
|
/// </summary>
|
||||||
|
Linear,
|
||||||
|
/// <summary>
|
||||||
|
/// A curve that starts a slowly and then accelerates until the end.
|
||||||
|
/// </summary>
|
||||||
|
EaseIn,
|
||||||
|
/// <summary>
|
||||||
|
/// A curve that starts a steep and then flattens until the end.
|
||||||
|
/// </summary>
|
||||||
|
EaseOut,
|
||||||
|
/// <summary>
|
||||||
|
/// A combination of the <see cref="CurvePreset.EaseIn"/> and <see cref="CurvePreset.EaseOut"/> preset.
|
||||||
|
/// </summary>
|
||||||
|
Smoothstep
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnKeyframesDeselect(IKeyframesEditor editor)
|
public override void OnKeyframesDeselect(IKeyframesEditor editor)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,48 @@ namespace FlaxEditor.GUI
|
|||||||
/// <seealso cref="CurveEditorBase" />
|
/// <seealso cref="CurveEditorBase" />
|
||||||
public abstract partial class CurveEditor<T> : CurveEditorBase where T : new()
|
public abstract partial class CurveEditor<T> : CurveEditorBase where T : new()
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single point in a <see cref="CurveEditorPreset"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected struct CurvePresetPoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The time.
|
||||||
|
/// </summary>
|
||||||
|
public float Time;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value.
|
||||||
|
/// </summary>
|
||||||
|
public float Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The in tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
public float TangentIn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The out tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
|
||||||
|
/// </summary>
|
||||||
|
public float TangentOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A curve preset.
|
||||||
|
/// </summary>
|
||||||
|
protected struct CurveEditorPreset()
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If the tangents will be linear or smooth.
|
||||||
|
/// </summary>
|
||||||
|
public bool LinearTangents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The points of the preset.
|
||||||
|
/// </summary>
|
||||||
|
public List<CurvePresetPoint> Points;
|
||||||
|
}
|
||||||
|
|
||||||
private class Popup : ContextMenuBase
|
private class Popup : ContextMenuBase
|
||||||
{
|
{
|
||||||
private CustomEditorPresenter _presenter;
|
private CustomEditorPresenter _presenter;
|
||||||
@@ -26,11 +68,12 @@ namespace FlaxEditor.GUI
|
|||||||
private List<int> _keyframeIndices;
|
private List<int> _keyframeIndices;
|
||||||
private bool _isDirty;
|
private bool _isDirty;
|
||||||
|
|
||||||
public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float height = 140.0f)
|
public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float maxHeight = 140.0f)
|
||||||
: this(editor, height)
|
: this(editor, maxHeight)
|
||||||
{
|
{
|
||||||
_presenter.Select(selection);
|
_presenter.Select(selection);
|
||||||
_presenter.OpenAllGroups();
|
_presenter.OpenAllGroups();
|
||||||
|
Size = new Float2(Size.X, Mathf.Min(_presenter.ContainerControl.Size.Y, maxHeight));
|
||||||
_keyframeIndices = keyframeIndices;
|
_keyframeIndices = keyframeIndices;
|
||||||
if (keyframeIndices != null && selection.Length != keyframeIndices.Count)
|
if (keyframeIndices != null && selection.Length != keyframeIndices.Count)
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
@@ -169,7 +212,7 @@ namespace FlaxEditor.GUI
|
|||||||
if (IsSelected)
|
if (IsSelected)
|
||||||
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
|
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
|
||||||
if (IsMouseOver)
|
if (IsMouseOver)
|
||||||
color *= 1.1f;
|
color *= 1.5f;
|
||||||
Render2D.FillRectangle(rect, color);
|
Render2D.FillRectangle(rect, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +328,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The keyframes size.
|
/// The keyframes size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected static readonly Float2 KeyframesSize = new Float2(7.0f);
|
protected static readonly Float2 KeyframesSize = new Float2(8.0f);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colors for the keyframe points.
|
/// The colors for the keyframe points.
|
||||||
@@ -326,6 +369,63 @@ namespace FlaxEditor.GUI
|
|||||||
private Color _labelsColor;
|
private Color _labelsColor;
|
||||||
private Font _labelsFont;
|
private Font _labelsFont;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preset values for <see cref="CurvePreset"/> to be applied to a <see cref="CurveEditor{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected Dictionary<CurvePreset, CurveEditorPreset> Presets = new Dictionary<CurvePreset, CurveEditorPreset>
|
||||||
|
{
|
||||||
|
{ CurvePreset.Constant, new CurveEditorPreset
|
||||||
|
{
|
||||||
|
LinearTangents = true,
|
||||||
|
Points = new List<CurvePresetPoint>
|
||||||
|
{
|
||||||
|
new CurvePresetPoint { Time = 0f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
new CurvePresetPoint { Time = 1f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ CurvePreset.EaseIn, new CurveEditorPreset
|
||||||
|
{
|
||||||
|
LinearTangents = false,
|
||||||
|
Points = new List<CurvePresetPoint>
|
||||||
|
{
|
||||||
|
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = -1.4f, TangentOut = 0f },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ CurvePreset.EaseOut, new CurveEditorPreset
|
||||||
|
{
|
||||||
|
LinearTangents = false,
|
||||||
|
Points = new List<CurvePresetPoint>
|
||||||
|
{
|
||||||
|
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 1.4f },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ CurvePreset.Linear, new CurveEditorPreset
|
||||||
|
{
|
||||||
|
LinearTangents = true,
|
||||||
|
Points = new List<CurvePresetPoint>
|
||||||
|
{
|
||||||
|
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ CurvePreset.Smoothstep, new CurveEditorPreset
|
||||||
|
{
|
||||||
|
LinearTangents = false,
|
||||||
|
Points = new List<CurvePresetPoint>
|
||||||
|
{
|
||||||
|
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The keyframe UI points.
|
/// The keyframe UI points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -568,6 +668,28 @@ namespace FlaxEditor.GUI
|
|||||||
/// <param name="indicesToRemove">The list of indices of the keyframes to remove.</param>
|
/// <param name="indicesToRemove">The list of indices of the keyframes to remove.</param>
|
||||||
protected abstract void RemoveKeyframesInternal(HashSet<int> indicesToRemove);
|
protected abstract void RemoveKeyframesInternal(HashSet<int> indicesToRemove);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to convert a float to the type of the type wildcard of the curve editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The float.</param>
|
||||||
|
/// <returns>The converted value.</returns>
|
||||||
|
public static object ConvertCurvePresetValueToCurveEditorType(float value)
|
||||||
|
{
|
||||||
|
if (typeof(T) == typeof(Float2))
|
||||||
|
return new Float2(value);
|
||||||
|
if (typeof(T) == typeof(Float3))
|
||||||
|
return new Float3(value);
|
||||||
|
if (typeof(T) == typeof(Float4))
|
||||||
|
return new Float4(value);
|
||||||
|
if (typeof(T) == typeof(Vector2))
|
||||||
|
return new Vector2(value);
|
||||||
|
if (typeof(T) == typeof(Vector3))
|
||||||
|
return new Vector3(value);
|
||||||
|
if (typeof(T) == typeof(Vector4))
|
||||||
|
return new Vector4(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when showing a context menu. Can be used to add custom buttons with actions.
|
/// Called when showing a context menu. Can be used to add custom buttons with actions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -752,6 +874,17 @@ namespace FlaxEditor.GUI
|
|||||||
ShowCurve(false);
|
ShowCurve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies a <see cref="CurvePreset"/> to the curve editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="preset">The preset.</param>
|
||||||
|
public virtual void ApplyPreset(CurvePreset preset)
|
||||||
|
{
|
||||||
|
// Remove existing keyframes
|
||||||
|
SelectAll();
|
||||||
|
RemoveKeyframes();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Evaluate(out object result, float time, bool loop = false)
|
public override void Evaluate(out object result, float time, bool loop = false)
|
||||||
{
|
{
|
||||||
@@ -1028,6 +1161,31 @@ namespace FlaxEditor.GUI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool left = key == KeyboardKeys.ArrowLeft;
|
||||||
|
bool right = key == KeyboardKeys.ArrowRight;
|
||||||
|
bool up = key == KeyboardKeys.ArrowUp;
|
||||||
|
bool down = key == KeyboardKeys.ArrowDown;
|
||||||
|
|
||||||
|
if (left || right || up || down)
|
||||||
|
{
|
||||||
|
bool shift = Root.GetKey(KeyboardKeys.Shift);
|
||||||
|
bool alt = Root.GetKey(KeyboardKeys.Alt);
|
||||||
|
float deltaValue = 10f;
|
||||||
|
if (shift || alt)
|
||||||
|
deltaValue = shift ? 2.5f : 5f;
|
||||||
|
|
||||||
|
Float2 moveDelta = Float2.Zero;
|
||||||
|
if (left || right)
|
||||||
|
moveDelta.X = left ? -deltaValue : deltaValue;
|
||||||
|
if (up || down)
|
||||||
|
moveDelta.Y = up ? -deltaValue : deltaValue;
|
||||||
|
|
||||||
|
_contents.OnMoveStart(Float2.Zero);
|
||||||
|
_contents.OnMove(moveDelta);
|
||||||
|
_contents.OnMoveEnd(Float2.Zero);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1526,6 +1684,22 @@ namespace FlaxEditor.GUI
|
|||||||
_tangents[i].Visible = false;
|
_tangents[i].Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ApplyPreset(CurvePreset preset)
|
||||||
|
{
|
||||||
|
base.ApplyPreset(preset);
|
||||||
|
|
||||||
|
CurveEditorPreset data = Presets[preset];
|
||||||
|
foreach (var point in data.Points)
|
||||||
|
{
|
||||||
|
float time = point.Time;
|
||||||
|
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
|
||||||
|
AddKeyframe(time, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowWholeCurve();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void DrawCurve(ref Rectangle viewRect)
|
protected override void DrawCurve(ref Rectangle viewRect)
|
||||||
{
|
{
|
||||||
@@ -2312,6 +2486,30 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ApplyPreset(CurvePreset preset)
|
||||||
|
{
|
||||||
|
base.ApplyPreset(preset);
|
||||||
|
|
||||||
|
CurveEditorPreset data = Presets[preset];
|
||||||
|
|
||||||
|
foreach (var point in data.Points)
|
||||||
|
{
|
||||||
|
float time = point.Time;
|
||||||
|
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
|
||||||
|
object tangentIn = ConvertCurvePresetValueToCurveEditorType((float)point.TangentIn);
|
||||||
|
object tangentOut = ConvertCurvePresetValueToCurveEditorType((float)point.TangentOut);
|
||||||
|
|
||||||
|
AddKeyframe(time, value, tangentIn, tangentOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectAll();
|
||||||
|
if (data.LinearTangents)
|
||||||
|
SetTangentsLinear();
|
||||||
|
|
||||||
|
ShowWholeCurve();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void SetScaleInternal(ref Float2 scale)
|
protected override void SetScaleInternal(ref Float2 scale)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
private bool _useDynamicEditing;
|
private bool _useDynamicEditing;
|
||||||
private bool _activeEyedropper;
|
private bool _activeEyedropper;
|
||||||
private bool _canPassLastChangeEvent = true;
|
private bool _canPassLastChangeEvent = true;
|
||||||
|
private bool _linear;
|
||||||
private ColorValueBox.ColorPickerEvent _onChanged;
|
private ColorValueBox.ColorPickerEvent _onChanged;
|
||||||
private ColorValueBox.ColorPickerClosedEvent _onClosed;
|
private ColorValueBox.ColorPickerClosedEvent _onClosed;
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
private Button _cCancel;
|
private Button _cCancel;
|
||||||
private Button _cOK;
|
private Button _cOK;
|
||||||
private Button _cEyedropper;
|
private Button _cEyedropper;
|
||||||
|
private Button _cLinearSRGB;
|
||||||
|
|
||||||
private List<Color> _savedColors = new List<Color>();
|
private List<Color> _savedColors = new List<Color>();
|
||||||
private List<Button> _savedColorButtons = new List<Button>();
|
private List<Button> _savedColorButtons = new List<Button>();
|
||||||
@@ -118,6 +120,7 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
_value = Color.Transparent;
|
_value = Color.Transparent;
|
||||||
_onChanged = colorChanged;
|
_onChanged = colorChanged;
|
||||||
_onClosed = pickerClosed;
|
_onClosed = pickerClosed;
|
||||||
|
_linear = !Graphics.GammaColorSpace;
|
||||||
|
|
||||||
// Get saved colors if they exist
|
// Get saved colors if they exist
|
||||||
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out string savedColors))
|
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out string savedColors))
|
||||||
@@ -227,6 +230,25 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
_cEyedropper.Width = _cEyedropper.Height;
|
_cEyedropper.Width = _cEyedropper.Height;
|
||||||
_cEyedropper.X -= _cEyedropper.Width;
|
_cEyedropper.X -= _cEyedropper.Width;
|
||||||
|
|
||||||
|
// Linear/sRGB toggle button
|
||||||
|
_cLinearSRGB = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin)
|
||||||
|
{
|
||||||
|
TooltipText = "Toggles between color preview in Linear and sRGB",
|
||||||
|
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.SplineAligned64),
|
||||||
|
BackgroundColor = _cEyedropper.BackgroundColor,
|
||||||
|
BackgroundColorHighlighted = _cEyedropper.BackgroundColorHighlighted,
|
||||||
|
BorderColor = _linear ? Color.Transparent : style.Foreground,
|
||||||
|
BorderColorHighlighted = _cEyedropper.BorderColorHighlighted,
|
||||||
|
Size = _cEyedropper.Size,
|
||||||
|
Parent = this,
|
||||||
|
Location = _cEyedropper.BottomLeft + new Float2(0, 4),
|
||||||
|
};
|
||||||
|
_cLinearSRGB.Clicked += () =>
|
||||||
|
{
|
||||||
|
_linear = !_linear;
|
||||||
|
_cLinearSRGB.BorderColor = _linear ? Color.Transparent : style.Foreground;
|
||||||
|
};
|
||||||
|
|
||||||
// Set initial color
|
// Set initial color
|
||||||
SelectedColor = initialValue;
|
SelectedColor = initialValue;
|
||||||
}
|
}
|
||||||
@@ -281,16 +303,22 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
if (_activeEyedropper)
|
if (_activeEyedropper)
|
||||||
{
|
{
|
||||||
_activeEyedropper = false;
|
_activeEyedropper = false;
|
||||||
SelectedColor = colorPicked;
|
if (colorPicked != Color.Transparent)
|
||||||
ScreenUtilities.PickColorDone -= OnColorPicked;
|
{
|
||||||
|
Color color = colorPicked;
|
||||||
|
if (_linear)
|
||||||
|
color = color.ToLinear();
|
||||||
|
SelectedColor = color;
|
||||||
|
}
|
||||||
|
Platform.PickScreenColorDone -= OnColorPicked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEyedropStart()
|
private void OnEyedropStart()
|
||||||
{
|
{
|
||||||
_activeEyedropper = true;
|
_activeEyedropper = true;
|
||||||
ScreenUtilities.PickColor();
|
Platform.PickScreenColor();
|
||||||
ScreenUtilities.PickColorDone += OnColorPicked;
|
Platform.PickScreenColorDone += OnColorPicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRGBAChanged()
|
private void OnRGBAChanged()
|
||||||
@@ -328,11 +356,15 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
{
|
{
|
||||||
// Try reading the color under the cursor in realtime if supported by the platform
|
// Try reading the color under the cursor in realtime if supported by the platform
|
||||||
Float2 mousePosition = Platform.MousePosition;
|
Float2 mousePosition = Platform.MousePosition;
|
||||||
Color color = ScreenUtilities.GetColorAt(mousePosition);
|
Color color = Platform.GetScreenColorAt(mousePosition);
|
||||||
if (color != Color.Transparent)
|
if (color != Color.Transparent)
|
||||||
|
{
|
||||||
|
if (_linear)
|
||||||
|
color = color.ToLinear();
|
||||||
SelectedColor = color;
|
SelectedColor = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
@@ -391,7 +423,7 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Render2D.FillRectangle(newRect, _value);
|
Render2D.FillRectangle(newRect, _linear ? _value.ToSRgb() : _value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -412,7 +444,7 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
{
|
{
|
||||||
// Cancel eye dropping
|
// Cancel eye dropping
|
||||||
_activeEyedropper = false;
|
_activeEyedropper = false;
|
||||||
ScreenUtilities.PickColorDone -= OnColorPicked;
|
Platform.PickScreenColorDone -= OnColorPicked;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,6 +310,26 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
Render2D.DrawRectangle(_slider1Rect, _isMouseDownSlider1 ? style.BackgroundSelected : Color.Black);
|
Render2D.DrawRectangle(_slider1Rect, _isMouseDownSlider1 ? style.BackgroundSelected : Color.Black);
|
||||||
Render2D.DrawRectangle(valueR, _isMouseDownSlider1 ? Color.White : Color.Gray);
|
Render2D.DrawRectangle(valueR, _isMouseDownSlider1 ? Color.White : Color.Gray);
|
||||||
|
|
||||||
|
// Draw checkerboard pattern to part of the alpha slider background
|
||||||
|
var alphaRect = _slider2Rect;
|
||||||
|
Render2D.FillRectangle(alphaRect, Color.White);
|
||||||
|
var smallRectSize = alphaRect.Width * 0.5f;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Alpha
|
// Alpha
|
||||||
float alphaY = _slider2Rect.Height * (1 - _color.A);
|
float alphaY = _slider2Rect.Height * (1 - _color.A);
|
||||||
var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);
|
var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
var childPanels = _childPanels.ToArray();
|
var childPanels = _childPanels.ToArray();
|
||||||
if (childPanels.Length != 0)
|
if (childPanels.Length != 0)
|
||||||
{
|
{
|
||||||
// Move tabs from child panels into this one
|
// Fallback: move tabs from child panels into this one.
|
||||||
DockWindow selectedTab = null;
|
DockWindow selectedTab = null;
|
||||||
foreach (var childPanel in childPanels)
|
foreach (var childPanel in childPanels)
|
||||||
{
|
{
|
||||||
@@ -490,7 +490,8 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
{
|
{
|
||||||
// Unlink splitter
|
// Unlink splitter
|
||||||
var splitterParent = splitter.Parent;
|
var splitterParent = splitter.Parent;
|
||||||
Assert.IsNotNull(splitterParent);
|
if (splitterParent == null)
|
||||||
|
return;
|
||||||
splitter.Parent = null;
|
splitter.Parent = null;
|
||||||
|
|
||||||
// Move controls from second split panel to the split panel parent
|
// Move controls from second split panel to the split panel parent
|
||||||
@@ -507,17 +508,63 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
splitter.Dispose();
|
splitter.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (IsMaster && _childPanels.Count != 0)
|
||||||
|
{
|
||||||
|
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (!IsMaster)
|
else if (!IsMaster)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (_childPanels.Count != 0)
|
||||||
|
{
|
||||||
|
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (!IsMaster)
|
else if (!IsMaster)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool CollapseEmptyTabsProxy()
|
||||||
|
{
|
||||||
|
if (TabsCount == 0 && ChildPanelsCount > 0)
|
||||||
|
{
|
||||||
|
return TryCollapseSplitter(_tabsProxy?.Parent as Panel);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryCollapseSplitter(Panel removedPanelParent)
|
||||||
|
{
|
||||||
|
if (removedPanelParent == null)
|
||||||
|
return false;
|
||||||
|
if (!(removedPanelParent.Parent is SplitPanel tabsSplitter))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var splitterParent = tabsSplitter.Parent;
|
||||||
|
if (splitterParent == null)
|
||||||
|
return false;
|
||||||
|
tabsSplitter.Parent = null;
|
||||||
|
|
||||||
|
var scrPanel = removedPanelParent == tabsSplitter.Panel2 ? tabsSplitter.Panel1 : tabsSplitter.Panel2;
|
||||||
|
var srcPanelChildrenCount = scrPanel.ChildrenCount;
|
||||||
|
for (int i = srcPanelChildrenCount - 1; i >= 0 && scrPanel.ChildrenCount > 0; i--)
|
||||||
|
{
|
||||||
|
scrPanel.GetChild(i).Parent = splitterParent;
|
||||||
|
}
|
||||||
|
Assert.IsTrue(scrPanel.ChildrenCount == 0);
|
||||||
|
Assert.IsTrue(splitterParent.ChildrenCount == srcPanelChildrenCount);
|
||||||
|
|
||||||
|
tabsSplitter.Dispose();
|
||||||
|
if (_tabsProxy != null && _tabsProxy.Parent == removedPanelParent)
|
||||||
|
_tabsProxy = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
|
internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
|
||||||
{
|
{
|
||||||
DockWindow(state, window, autoSelect, splitterValue);
|
DockWindow(state, window, autoSelect, splitterValue);
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
{
|
{
|
||||||
CreateFloating(Float2.Zero, Float2.Zero);
|
CreateFloating(Float2.Zero, Float2.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the window in a floating state.
|
/// Creates the window in a floating state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -108,7 +108,11 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Create docking hint window
|
// Create docking hint window
|
||||||
WindowDragHelper.StartDragging(this);
|
Window dragSourceWindow = null;
|
||||||
|
#if !PLATFORM_SDL
|
||||||
|
dragSourceWindow = _window?.Window;
|
||||||
|
#endif
|
||||||
|
WindowDragHelper.StartDragging(this, dragSourceWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -127,11 +131,15 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
settings.Title = title;
|
settings.Title = title;
|
||||||
settings.Size = size;
|
settings.Size = size;
|
||||||
settings.Position = location;
|
settings.Position = location;
|
||||||
settings.MinimumSize = new Float2(200, 150);
|
settings.MinimumSize = new Float2(100, 100);
|
||||||
settings.MaximumSize = Float2.Zero; // Unlimited size
|
settings.MaximumSize = Float2.Zero; // Unlimited size
|
||||||
settings.Fullscreen = false;
|
settings.Fullscreen = false;
|
||||||
settings.HasBorder = true;
|
settings.HasBorder = true;
|
||||||
|
#if PLATFORM_SDL
|
||||||
settings.SupportsTransparency = true;
|
settings.SupportsTransparency = true;
|
||||||
|
#else
|
||||||
|
settings.SupportsTransparency = false;
|
||||||
|
#endif
|
||||||
settings.ActivateWhenFirstShown = true;
|
settings.ActivateWhenFirstShown = true;
|
||||||
settings.AllowInput = true;
|
settings.AllowInput = true;
|
||||||
settings.AllowMinimize = true;
|
settings.AllowMinimize = true;
|
||||||
@@ -213,7 +221,12 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
base.OnSelectedTabChanged();
|
base.OnSelectedTabChanged();
|
||||||
|
|
||||||
if (_window != null && SelectedTab != null)
|
if (_window != null && SelectedTab != null)
|
||||||
|
{
|
||||||
_window.Title = SelectedTab.Title;
|
_window.Title = SelectedTab.Title;
|
||||||
|
var decorations = Parent.GetChild<FloatWindowDecorations>();
|
||||||
|
if (decorations != null)
|
||||||
|
decorations.PerformLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hint control size.
|
/// The hint control size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const float HintControlSize = 32.0f;
|
public const float HintControlSize = 48.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The opacity of the dragged window when hint controls are shown.
|
/// The opacity of the dragged window when hint controls are shown.
|
||||||
@@ -44,13 +44,33 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
_toMove = toMove;
|
_toMove = toMove;
|
||||||
_toSet = DockState.Float;
|
_toSet = DockState.Float;
|
||||||
var window = toMove.Window.Window;
|
var window = toMove.Window.Window;
|
||||||
|
var mousePos = Platform.MousePosition;
|
||||||
|
|
||||||
|
// Check if window is maximized and restore window for correct dragging
|
||||||
|
if (window.IsMaximized)
|
||||||
|
{
|
||||||
|
var windowMousePos = mousePos - window.Position;
|
||||||
|
var previousSize = window.Size;
|
||||||
|
window.Restore();
|
||||||
|
window.Position = mousePos - windowMousePos * window.Size / previousSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When drag starts from a tabs the window might not be shown yet
|
||||||
|
if (!window.IsVisible)
|
||||||
|
{
|
||||||
|
window.Show();
|
||||||
|
window.Position = mousePos - new Float2(40, 10);
|
||||||
|
}
|
||||||
|
|
||||||
// Bind events
|
// Bind events
|
||||||
FlaxEngine.Scripting.Update += OnUpdate;
|
FlaxEngine.Scripting.Update += OnUpdate;
|
||||||
window.MouseUp += OnMouseUp;
|
window.MouseUp += OnMouseUp;
|
||||||
|
#if !PLATFORM_SDL
|
||||||
|
window.StartTrackingMouse(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update rectangles
|
// Update rectangles
|
||||||
UpdateRects(Platform.MousePosition);
|
UpdateRects(mousePos);
|
||||||
|
|
||||||
// Ensure the dragged window stays on top of every other window
|
// Ensure the dragged window stays on top of every other window
|
||||||
window.IsAlwaysOnTop = true;
|
window.IsAlwaysOnTop = true;
|
||||||
@@ -58,13 +78,21 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
_dragSourceWindow = dragSourceWindow;
|
_dragSourceWindow = dragSourceWindow;
|
||||||
if (_dragSourceWindow != null) // Detaching a tab from existing window
|
if (_dragSourceWindow != null) // Detaching a tab from existing window
|
||||||
{
|
{
|
||||||
|
#if PLATFORM_SDL
|
||||||
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
|
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
|
||||||
|
#else
|
||||||
|
_dragOffset = mousePos - window.Position;
|
||||||
|
#endif
|
||||||
|
|
||||||
_dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows
|
// The mouse up event is sent to the source window on Windows
|
||||||
|
_dragSourceWindow.MouseUp += OnMouseUp;
|
||||||
|
|
||||||
// TODO: when detaching tab in floating window (not main window), the drag source window is still main window?
|
// TODO: when detaching tab in floating window (not main window), the drag source window is still main window?
|
||||||
var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow;
|
var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow;
|
||||||
window.DoDragDrop(window.Title, _dragOffset, dragSourceWindowWayland);
|
window.DoDragDrop(window.Title, _dragOffset, dragSourceWindowWayland);
|
||||||
|
#if !PLATFORM_SDL
|
||||||
|
_dragSourceWindow.BringToFront();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -84,7 +112,12 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
// Unbind events
|
// Unbind events
|
||||||
FlaxEngine.Scripting.Update -= OnUpdate;
|
FlaxEngine.Scripting.Update -= OnUpdate;
|
||||||
if (window != null)
|
if (window != null)
|
||||||
|
{
|
||||||
window.MouseUp -= OnMouseUp;
|
window.MouseUp -= OnMouseUp;
|
||||||
|
#if !PLATFORM_SDL
|
||||||
|
window.EndTrackingMouse();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (_dragSourceWindow != null)
|
if (_dragSourceWindow != null)
|
||||||
_dragSourceWindow.MouseUp -= OnMouseUp;
|
_dragSourceWindow.MouseUp -= OnMouseUp;
|
||||||
|
|
||||||
@@ -160,13 +193,14 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// Start dragging a floating dock panel.
|
/// Start dragging a floating dock panel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="toMove">Floating dock panel to move.</param>
|
/// <param name="toMove">Floating dock panel to move.</param>
|
||||||
|
/// <param name="dragSourceWindow">The window where dragging started from.</param>
|
||||||
/// <returns>The window drag helper object.</returns>
|
/// <returns>The window drag helper object.</returns>
|
||||||
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove)
|
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove, Window dragSourceWindow = null)
|
||||||
{
|
{
|
||||||
if (toMove == null)
|
if (toMove == null)
|
||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
return new WindowDragHelper(toMove, null);
|
return new WindowDragHelper(toMove, dragSourceWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -268,7 +302,8 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prefer panel in the same window we hit earlier
|
// Prefer panel in the same window we hit earlier
|
||||||
if (dockPanel?.RootWindow != _toDock?.RootWindow)
|
// TODO: this doesn't allow docking window into another floating window over the main window
|
||||||
|
/*if (dockPanel?.RootWindow != _toDock?.RootWindow)
|
||||||
{
|
{
|
||||||
foreach (var hit in hitResults)
|
foreach (var hit in hitResults)
|
||||||
{
|
{
|
||||||
@@ -278,7 +313,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dockPanel != _toDock)
|
if (dockPanel != _toDock)
|
||||||
@@ -288,11 +323,18 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
AddDockHints();
|
AddDockHints();
|
||||||
|
|
||||||
// Make sure the all the dock hint areas are not under other windows
|
// Make sure the all the dock hint areas are not under other windows
|
||||||
|
if (_toDock != Editor.Instance.UI.MasterPanel)
|
||||||
_toDock?.RootWindow.Window.BringToFront();
|
_toDock?.RootWindow.Window.BringToFront();
|
||||||
//_toDock?.RootWindow.Window.Focus();
|
//_toDock?.RootWindow.Window.Focus();
|
||||||
|
|
||||||
|
#if PLATFORM_SDL
|
||||||
// Make the dragged window transparent when dock hints are visible
|
// Make the dragged window transparent when dock hints are visible
|
||||||
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
|
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
|
||||||
|
#else
|
||||||
|
// Bring the drop source always to the top
|
||||||
|
if (_dragSourceWindow != null)
|
||||||
|
_dragSourceWindow.BringToFront();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check dock state to use
|
// Check dock state to use
|
||||||
@@ -300,7 +342,10 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
bool showBorderHints = showProxyHints;
|
bool showBorderHints = showProxyHints;
|
||||||
bool showCenterHint = showProxyHints;
|
bool showCenterHint = showProxyHints;
|
||||||
Control hoveredHintControl = null;
|
Control hoveredHintControl = null;
|
||||||
|
Float2 hoveredLocationOffset = Float2.Zero;
|
||||||
Float2 hoveredSizeOverride = Float2.Zero;
|
Float2 hoveredSizeOverride = Float2.Zero;
|
||||||
|
DockState prevToSet = _toSet;
|
||||||
|
float hoveredMargin = 1.0f;
|
||||||
if (showProxyHints)
|
if (showProxyHints)
|
||||||
{
|
{
|
||||||
// If moved window has not only tabs but also child panels disable docking as tab
|
// If moved window has not only tabs but also child panels disable docking as tab
|
||||||
@@ -317,7 +362,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
// Cache dock rectangles
|
// Cache dock rectangles
|
||||||
var size = _rectDock.Size / Platform.DpiScale;
|
var size = _rectDock.Size / Platform.DpiScale;
|
||||||
var offset = _toDock.PointFromScreen(_rectDock.Location);
|
var offset = _toDock.PointFromScreen(_rectDock.Location);
|
||||||
var borderMargin = 4.0f;
|
var borderMargin = 10.0f;
|
||||||
var hintWindowsSize = HintControlSize;
|
var hintWindowsSize = HintControlSize;
|
||||||
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
||||||
var hintPreviewSize = new Float2(Math.Max(HintControlSize * 2, size.X * 0.5f), Math.Max(HintControlSize * 2, size.Y * 0.5f));
|
var hintPreviewSize = new Float2(Math.Max(HintControlSize * 2, size.X * 0.5f), Math.Max(HintControlSize * 2, size.Y * 0.5f));
|
||||||
@@ -330,35 +375,40 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
|
||||||
// Hit test, and calculate the approximation for filled area when hovered over the hint
|
// Hit test, and calculate the approximation for filled area when hovered over the hint
|
||||||
DockState toSet = DockState.Float;
|
var toSet = DockState.Float;
|
||||||
|
var hintTestPoint = _toDock.PointFromScreen(_mouse);
|
||||||
if (showBorderHints)
|
if (showBorderHints)
|
||||||
{
|
{
|
||||||
if (_rUpper.Contains(_toDock.PointFromScreen(_mouse)))
|
if (_rUpper.Contains(ref hintTestPoint))
|
||||||
{
|
{
|
||||||
toSet = DockState.DockTop;
|
toSet = DockState.DockTop;
|
||||||
hoveredHintControl = _dockHintUp;
|
hoveredHintControl = _dockHintUp;
|
||||||
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
hoveredSizeOverride = new Float2(size.X, size.Y * DockPanel.DefaultSplitterValue);
|
||||||
|
hoveredLocationOffset.Y -= borderMargin - hoveredMargin;
|
||||||
}
|
}
|
||||||
else if (_rBottom.Contains(_toDock.PointFromScreen(_mouse)))
|
else if (_rBottom.Contains(ref hintTestPoint))
|
||||||
{
|
{
|
||||||
toSet = DockState.DockBottom;
|
toSet = DockState.DockBottom;
|
||||||
hoveredHintControl = _dockHintDown;
|
hoveredHintControl = _dockHintDown;
|
||||||
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
hoveredSizeOverride = new Float2(size.X, size.Y * DockPanel.DefaultSplitterValue);
|
||||||
|
hoveredLocationOffset.Y += borderMargin - hoveredMargin;
|
||||||
}
|
}
|
||||||
else if (_rLeft.Contains(_toDock.PointFromScreen(_mouse)))
|
else if (_rLeft.Contains(ref hintTestPoint))
|
||||||
{
|
{
|
||||||
toSet = DockState.DockLeft;
|
toSet = DockState.DockLeft;
|
||||||
hoveredHintControl = _dockHintLeft;
|
hoveredHintControl = _dockHintLeft;
|
||||||
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
|
hoveredSizeOverride = new Float2(size.X * DockPanel.DefaultSplitterValue, size.Y);
|
||||||
|
hoveredLocationOffset.X -= borderMargin - hoveredMargin;
|
||||||
}
|
}
|
||||||
else if (_rRight.Contains(_toDock.PointFromScreen(_mouse)))
|
else if (_rRight.Contains(ref hintTestPoint))
|
||||||
{
|
{
|
||||||
toSet = DockState.DockRight;
|
toSet = DockState.DockRight;
|
||||||
hoveredHintControl = _dockHintRight;
|
hoveredHintControl = _dockHintRight;
|
||||||
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
|
hoveredSizeOverride = new Float2(size.X * DockPanel.DefaultSplitterValue, size.Y);
|
||||||
|
hoveredLocationOffset.X += borderMargin - hoveredMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (showCenterHint && _rCenter.Contains(_toDock.PointFromScreen(_mouse)))
|
if (showCenterHint && _rCenter.Contains(ref hintTestPoint))
|
||||||
{
|
{
|
||||||
toSet = DockState.DockFill;
|
toSet = DockState.DockFill;
|
||||||
hoveredHintControl = _dockHintCenter;
|
hoveredHintControl = _dockHintCenter;
|
||||||
@@ -375,38 +425,41 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
// Update sizes and opacity of hint controls
|
// Update sizes and opacity of hint controls
|
||||||
if (_toDock != null)
|
if (_toDock != null)
|
||||||
{
|
{
|
||||||
|
var mainColor = Style.Current.Selection;
|
||||||
if (hoveredHintControl != _dockHintDown)
|
if (hoveredHintControl != _dockHintDown)
|
||||||
{
|
{
|
||||||
_dockHintDown.Size = new Float2(HintControlSize);
|
_dockHintDown.Size = new Float2(HintControlSize);
|
||||||
_dockHintDown.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
_dockHintDown.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
|
||||||
}
|
}
|
||||||
if (hoveredHintControl != _dockHintLeft)
|
if (hoveredHintControl != _dockHintLeft)
|
||||||
{
|
{
|
||||||
_dockHintLeft.Size = new Float2(HintControlSize);
|
_dockHintLeft.Size = new Float2(HintControlSize);
|
||||||
_dockHintLeft.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
_dockHintLeft.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
|
||||||
}
|
}
|
||||||
if (hoveredHintControl != _dockHintRight)
|
if (hoveredHintControl != _dockHintRight)
|
||||||
{
|
{
|
||||||
_dockHintRight.Size = new Float2(HintControlSize);
|
_dockHintRight.Size = new Float2(HintControlSize);
|
||||||
_dockHintRight.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
_dockHintRight.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
|
||||||
}
|
}
|
||||||
if (hoveredHintControl != _dockHintUp)
|
if (hoveredHintControl != _dockHintUp)
|
||||||
{
|
{
|
||||||
_dockHintUp.Size = new Float2(HintControlSize);
|
_dockHintUp.Size = new Float2(HintControlSize);
|
||||||
_dockHintUp.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
_dockHintUp.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
|
||||||
}
|
}
|
||||||
if (hoveredHintControl != _dockHintCenter)
|
if (hoveredHintControl != _dockHintCenter)
|
||||||
{
|
{
|
||||||
_dockHintCenter.Size = new Float2(HintControlSize);
|
_dockHintCenter.Size = new Float2(HintControlSize);
|
||||||
_dockHintCenter.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
_dockHintCenter.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_toSet != DockState.Float)
|
if (_toSet != DockState.Float)
|
||||||
{
|
{
|
||||||
if (hoveredHintControl != null)
|
if (hoveredHintControl != null)
|
||||||
{
|
{
|
||||||
hoveredHintControl.BackgroundColor = Style.Current.Selection.AlphaMultiplied(1.0f);
|
hoveredHintControl.BackgroundColor = mainColor;
|
||||||
hoveredHintControl.Size = hoveredSizeOverride;
|
if (_toSet != prevToSet)
|
||||||
|
hoveredHintControl.Location += hoveredLocationOffset;
|
||||||
|
hoveredHintControl.Size = hoveredSizeOverride - hoveredMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,13 +494,15 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
|
|
||||||
private void OnUpdate()
|
private void OnUpdate()
|
||||||
{
|
{
|
||||||
var mousePos = Platform.MousePosition;
|
// If the engine lost focus during dragging, end the action
|
||||||
|
if (!Engine.HasFocus)
|
||||||
if (_mouse != mousePos)
|
{
|
||||||
OnMouseMove(mousePos);
|
Dispose();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMouseMove(Float2 mousePos)
|
var mousePos = Platform.MousePosition;
|
||||||
|
if (_mouse != mousePos)
|
||||||
{
|
{
|
||||||
if (_dragSourceWindow != null)
|
if (_dragSourceWindow != null)
|
||||||
_toMove.Window.Window.Position = mousePos - _dragOffset;
|
_toMove.Window.Window.Position = mousePos - _dragOffset;
|
||||||
@@ -456,3 +511,4 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -242,6 +242,15 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
FieldInfo[] fields = type.GetFields();
|
FieldInfo[] fields = type.GetFields();
|
||||||
entries.Capacity = Mathf.Max(fields.Length - 1, entries.Capacity);
|
entries.Capacity = Mathf.Max(fields.Length - 1, entries.Capacity);
|
||||||
|
if (formatMode == EnumDisplayAttribute.FormatMode.Default)
|
||||||
|
{
|
||||||
|
// Override display mode from enum itself
|
||||||
|
var attr = type.GetCustomAttribute<EnumDisplayAttribute>();
|
||||||
|
if (attr != null)
|
||||||
|
{
|
||||||
|
formatMode = attr.Mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = 0; i < fields.Length; i++)
|
for (int i = 0; i < fields.Length; i++)
|
||||||
{
|
{
|
||||||
var field = fields[i];
|
var field = fields[i];
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace FlaxEditor.GUI.Input
|
|||||||
public class ColorValueBox : Control
|
public class ColorValueBox : Control
|
||||||
{
|
{
|
||||||
private bool _isMouseDown;
|
private bool _isMouseDown;
|
||||||
|
private bool _linear;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delegate function used for the color picker events handling.
|
/// Delegate function used for the color picker events handling.
|
||||||
@@ -101,6 +102,7 @@ namespace FlaxEditor.GUI.Input
|
|||||||
public ColorValueBox()
|
public ColorValueBox()
|
||||||
: base(0, 0, 32, 18)
|
: base(0, 0, 32, 18)
|
||||||
{
|
{
|
||||||
|
_linear = !Graphics.GammaColorSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -113,6 +115,7 @@ namespace FlaxEditor.GUI.Input
|
|||||||
: base(x, y, 32, 18)
|
: base(x, y, 32, 18)
|
||||||
{
|
{
|
||||||
_value = value;
|
_value = value;
|
||||||
|
_linear = !Graphics.GammaColorSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -129,8 +132,10 @@ namespace FlaxEditor.GUI.Input
|
|||||||
{
|
{
|
||||||
base.Draw();
|
base.Draw();
|
||||||
|
|
||||||
bool isTransparent = _value.A < 1;
|
var value = _value;
|
||||||
|
if (_linear)
|
||||||
|
value = value.ToSRgb();
|
||||||
|
var isTransparent = value.A < 1;
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var fullRect = new Rectangle(0, 0, Width, Height);
|
var fullRect = new Rectangle(0, 0, Width, Height);
|
||||||
var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height);
|
var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height);
|
||||||
@@ -157,10 +162,10 @@ namespace FlaxEditor.GUI.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Render2D.FillRectangle(alphaRect, _value);
|
Render2D.FillRectangle(alphaRect, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Render2D.FillRectangle(colorRect, _value with { A = 1 });
|
Render2D.FillRectangle(colorRect, value with { A = 1 });
|
||||||
Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
|
Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ namespace FlaxEditor.GUI.Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action SlidingEnd;
|
public event Action SlidingEnd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If enabled, pressing the arrow up or down key increments/ decrements the value.
|
||||||
|
/// </summary>
|
||||||
|
public bool ArrowKeysIncrement = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the slider speed. Use value 0 to disable and hide slider UI.
|
/// Gets or sets the slider speed. Use value 0 to disable and hide slider UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -239,6 +244,27 @@ namespace FlaxEditor.GUI.Input
|
|||||||
ResetViewOffset();
|
ResetViewOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool OnKeyDown(KeyboardKeys key)
|
||||||
|
{
|
||||||
|
if (ArrowKeysIncrement && (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown))
|
||||||
|
{
|
||||||
|
bool altDown = Root.GetKey(KeyboardKeys.Alt);
|
||||||
|
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||||
|
bool controlDown = Root.GetKey(KeyboardKeys.Control);
|
||||||
|
float deltaValue = altDown ? 0.1f : (shiftDown ? 10f : (controlDown ? 100f : 1f));
|
||||||
|
float slideDelta = key == KeyboardKeys.ArrowUp ? deltaValue : -deltaValue;
|
||||||
|
|
||||||
|
_startSlideValue = Value;
|
||||||
|
ApplySliding(slideDelta);
|
||||||
|
EndSliding();
|
||||||
|
Focus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnKeyDown(key);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||||
{
|
{
|
||||||
@@ -296,7 +322,7 @@ namespace FlaxEditor.GUI.Input
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnMouseMoveRelative(Float2 mouseMotion)
|
public override void OnMouseMoveRelative(Float2 motion)
|
||||||
{
|
{
|
||||||
var location = Root.TrackingMouseOffset;
|
var location = Root.TrackingMouseOffset;
|
||||||
if (_isSliding)
|
if (_isSliding)
|
||||||
@@ -318,7 +344,7 @@ namespace FlaxEditor.GUI.Input
|
|||||||
_cursorChanged = false;
|
_cursorChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnMouseMoveRelative(mouseMotion);
|
base.OnMouseMoveRelative(motion);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -59,12 +59,12 @@ namespace FlaxEditor.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when items gets clicked by the user.
|
/// Occurs when items gets clicked by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<Item> Clicked;
|
public event Action<Item> ItemClicked;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when items gets focused.
|
/// Occurs when items gets focused.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<Item> Focused;
|
public event Action<Item> ItemFocused;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tint color of the text.
|
/// The tint color of the text.
|
||||||
@@ -203,7 +203,7 @@ namespace FlaxEditor.GUI
|
|||||||
if (button == MouseButton.Left && _isMouseDown)
|
if (button == MouseButton.Left && _isMouseDown)
|
||||||
{
|
{
|
||||||
_isMouseDown = false;
|
_isMouseDown = false;
|
||||||
Clicked?.Invoke(this);
|
ItemClicked?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseUp(location, button);
|
return base.OnMouseUp(location, button);
|
||||||
@@ -222,7 +222,7 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
base.OnGotFocus();
|
base.OnGotFocus();
|
||||||
|
|
||||||
Focused?.Invoke(this);
|
ItemFocused?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -434,7 +434,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
public void AddItem(Item item)
|
public void AddItem(Item item)
|
||||||
{
|
{
|
||||||
item.Clicked += OnClickItem;
|
item.ItemClicked += OnClickItem;
|
||||||
ContainerControl parent = ItemsPanel;
|
ContainerControl parent = ItemsPanel;
|
||||||
if (!string.IsNullOrEmpty(item.Category))
|
if (!string.IsNullOrEmpty(item.Category))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ namespace FlaxEditor.GUI
|
|||||||
new PlatformData(PlatformType.PS5, icons.PS5Icon128, "PlayStation 5"),
|
new PlatformData(PlatformType.PS5, icons.PS5Icon128, "PlayStation 5"),
|
||||||
new PlatformData(PlatformType.Mac, icons.MacOSIcon128, "macOS"),
|
new PlatformData(PlatformType.Mac, icons.MacOSIcon128, "macOS"),
|
||||||
new PlatformData(PlatformType.iOS, icons.IOSIcon128, "iOS"),
|
new PlatformData(PlatformType.iOS, icons.IOSIcon128, "iOS"),
|
||||||
|
new PlatformData(PlatformType.Web, icons.Flax64, "Web"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const float IconSize = 64.0f;
|
const float IconSize = 64.0f;
|
||||||
|
|||||||
@@ -201,9 +201,8 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
var idx = stream.ReadInt32();
|
var idx = stream.ReadInt32();
|
||||||
var id = stream.ReadGuid();
|
var id = stream.ReadGuid();
|
||||||
object value = null;
|
object value = null;
|
||||||
if (version == 2)
|
if (version <= 2)
|
||||||
stream.ReadCommonValue(ref value);
|
throw new Exception("Not supported asset version. Open and re-save asset with Flax 1.11.");
|
||||||
else
|
|
||||||
value = stream.ReadVariant();
|
value = stream.ReadVariant();
|
||||||
|
|
||||||
Emitters[idx].ParametersOverrides.Add(id, value);
|
Emitters[idx].ParametersOverrides.Add(id, value);
|
||||||
|
|||||||
@@ -1140,8 +1140,11 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
ParentTree.DraggedOverNode = this;
|
ParentTree.DraggedOverNode = this;
|
||||||
|
|
||||||
// Expand node if mouse goes over arrow
|
// Expand node if mouse goes over arrow
|
||||||
if (ArrowRect.Contains(location) && HasAnyVisibleChild)
|
if (ArrowRect.Contains(location) && HasAnyVisibleChild && IsCollapsed)
|
||||||
|
{
|
||||||
Expand(true);
|
Expand(true);
|
||||||
|
ParentTree?.FlushPendingPerformLayout();
|
||||||
|
}
|
||||||
|
|
||||||
result = OnDragEnterHeader(data);
|
result = OnDragEnterHeader(data);
|
||||||
}
|
}
|
||||||
@@ -1172,8 +1175,11 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
ParentTree.DraggedOverNode = this;
|
ParentTree.DraggedOverNode = this;
|
||||||
|
|
||||||
// Expand node if mouse goes over arrow
|
// Expand node if mouse goes over arrow
|
||||||
if (ArrowRect.Contains(location) && HasAnyVisibleChild)
|
if (ArrowRect.Contains(location) && HasAnyVisibleChild && IsCollapsed)
|
||||||
|
{
|
||||||
Expand(true);
|
Expand(true);
|
||||||
|
ParentTree?.FlushPendingPerformLayout();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_isDragOverHeader)
|
if (!_isDragOverHeader)
|
||||||
result = OnDragEnterHeader(data);
|
result = OnDragEnterHeader(data);
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
|
||||||
using FlaxEditor.GUI.Docking;
|
|
||||||
using FlaxEditor.Options;
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
public abstract class GizmoBase
|
public abstract class GizmoBase
|
||||||
{
|
{
|
||||||
private IGizmoOwner _owner;
|
private IGizmoOwner _owner;
|
||||||
|
private bool _visible = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the gizmo owner.
|
/// Gets the gizmo owner.
|
||||||
@@ -34,6 +35,11 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual BoundingSphere FocusBounds => BoundingSphere.Empty;
|
public virtual BoundingSphere FocusBounds => BoundingSphere.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this gizmo is visible.
|
||||||
|
/// </summary>
|
||||||
|
public bool Visible { get { return _visible; } set { _visible = value; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GizmoBase"/> class.
|
/// Initializes a new instance of the <see cref="GizmoBase"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ public sealed class ViewportRubberBandSelector
|
|||||||
/// Triggers the start of a rubber band selection.
|
/// Triggers the start of a rubber band selection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if selection started, otherwise false.</returns>
|
/// <returns>True if selection started, otherwise false.</returns>
|
||||||
public bool TryStartingRubberBandSelection()
|
public bool TryStartingRubberBandSelection(Float2 mousePosition)
|
||||||
{
|
{
|
||||||
if (!_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
if (!_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
||||||
{
|
{
|
||||||
_tryStartRubberBand = true;
|
_tryStartRubberBand = true;
|
||||||
|
_cachedStartingMousePosition = mousePosition;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -82,13 +83,16 @@ public sealed class ViewportRubberBandSelector
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tryStartRubberBand && (Mathf.Abs(_owner.MouseDelta.X) > 0.1f || Mathf.Abs(_owner.MouseDelta.Y) > 0.1f) && canStart)
|
if (_tryStartRubberBand && canStart)
|
||||||
|
{
|
||||||
|
var delta = mousePosition - _cachedStartingMousePosition;
|
||||||
|
if (Mathf.Abs(delta.X) > 0.1f || Mathf.Abs(delta.Y) > 0.1f)
|
||||||
{
|
{
|
||||||
_isRubberBandSpanning = true;
|
_isRubberBandSpanning = true;
|
||||||
_cachedStartingMousePosition = mousePosition;
|
|
||||||
_rubberBandRect = new Rectangle(_cachedStartingMousePosition, Float2.Zero);
|
_rubberBandRect = new Rectangle(_cachedStartingMousePosition, Float2.Zero);
|
||||||
_tryStartRubberBand = false;
|
_tryStartRubberBand = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
else if (_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
||||||
{
|
{
|
||||||
_rubberBandRect.Width = mousePosition.X - _cachedStartingMousePosition.X;
|
_rubberBandRect.Width = mousePosition.X - _cachedStartingMousePosition.X;
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace FlaxEditor.Modules
|
|||||||
/// <seealso cref="FlaxEditor.Modules.EditorModule" />
|
/// <seealso cref="FlaxEditor.Modules.EditorModule" />
|
||||||
public sealed class SceneEditingModule : EditorModule
|
public sealed class SceneEditingModule : EditorModule
|
||||||
{
|
{
|
||||||
|
private int _lastSelectionStatus = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The selected objects.
|
/// The selected objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -193,6 +195,20 @@ namespace FlaxEditor.Modules
|
|||||||
Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo));
|
Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo));
|
||||||
|
|
||||||
OnSelectionChanged();
|
OnSelectionChanged();
|
||||||
|
|
||||||
|
// Display amount of selected actors on the status bar
|
||||||
|
Editor.UI.RemoveStatusMessage(_lastSelectionStatus);
|
||||||
|
var objects = Selection.Count;
|
||||||
|
var actors = CountActors(Selection);
|
||||||
|
_lastSelectionStatus = Editor.UI.AddStatusMessage($"Selected {objects} {(objects > 1 ? "objects" : "object")} (total {actors} {(actors > 1 ? "actors" : "actor")})");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CountActors(List<SceneGraphNode> nodes)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
foreach (var node in nodes)
|
||||||
|
result += 1 + CountActors(node.ChildNodes);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSelectionUndo(SceneGraphNode[] toSelect)
|
private void OnSelectionUndo(SceneGraphNode[] toSelect)
|
||||||
@@ -229,7 +245,7 @@ namespace FlaxEditor.Modules
|
|||||||
if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && node.AffectsNavigationWithChildren)
|
if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && node.AffectsNavigationWithChildren)
|
||||||
{
|
{
|
||||||
var bounds = actor.BoxWithChildren;
|
var bounds = actor.BoxWithChildren;
|
||||||
Navigation.BuildNavMesh(actor.Scene, bounds, options.General.AutoRebuildNavMeshTimeoutMs);
|
Navigation.BuildNavMesh(bounds, options.General.AutoRebuildNavMeshTimeoutMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,18 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct Status
|
||||||
|
{
|
||||||
|
public int ID;
|
||||||
|
public string Text;
|
||||||
|
public DateTime EndTime;
|
||||||
|
}
|
||||||
|
|
||||||
private Label _progressLabel;
|
private Label _progressLabel;
|
||||||
private ProgressBar _progressBar;
|
private ProgressBar _progressBar;
|
||||||
private Button _outputLogButton;
|
private Button _outputLogButton;
|
||||||
private List<KeyValuePair<string, DateTime>> _statusMessages;
|
private List<Status> _statusMessages;
|
||||||
|
private int _statusID = 1;
|
||||||
private ContentStats _contentStats;
|
private ContentStats _contentStats;
|
||||||
private bool _progressFailed;
|
private bool _progressFailed;
|
||||||
|
|
||||||
@@ -158,6 +166,7 @@ namespace FlaxEditor.Modules
|
|||||||
private ContextMenuButton _menuToolsProfilerWindow;
|
private ContextMenuButton _menuToolsProfilerWindow;
|
||||||
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
|
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
|
||||||
private ContextMenuButton _menuToolsTakeScreenshot;
|
private ContextMenuButton _menuToolsTakeScreenshot;
|
||||||
|
private ContextMenuButton _menuToolsOpenLocalFolder;
|
||||||
private ContextMenuChildMenu _menuWindowApplyWindowLayout;
|
private ContextMenuChildMenu _menuWindowApplyWindowLayout;
|
||||||
|
|
||||||
private ToolStripButton _toolStripSaveAll;
|
private ToolStripButton _toolStripSaveAll;
|
||||||
@@ -378,7 +387,7 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
string text;
|
string text;
|
||||||
if (_statusMessages != null && _statusMessages.Count != 0)
|
if (_statusMessages != null && _statusMessages.Count != 0)
|
||||||
text = _statusMessages[0].Key;
|
text = _statusMessages[0].Text;
|
||||||
else if (Editor.StateMachine.CurrentState.Status != null)
|
else if (Editor.StateMachine.CurrentState.Status != null)
|
||||||
text = Editor.StateMachine.CurrentState.Status;
|
text = Editor.StateMachine.CurrentState.Status;
|
||||||
else if (contentStats.LoadingAssetsCount != 0)
|
else if (contentStats.LoadingAssetsCount != 0)
|
||||||
@@ -400,13 +409,34 @@ namespace FlaxEditor.Modules
|
|||||||
/// Adds the status bar message text to be displayed as a notification.
|
/// Adds the status bar message text to be displayed as a notification.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to display.</param>
|
/// <param name="message">The message to display.</param>
|
||||||
public void AddStatusMessage(string message)
|
/// <returns>The ID of that status message (unique). Can be used to hide it manually.</returns>
|
||||||
|
public int AddStatusMessage(string message)
|
||||||
{
|
{
|
||||||
if (_statusMessages == null)
|
if (_statusMessages == null)
|
||||||
_statusMessages = new List<KeyValuePair<string, DateTime>>();
|
_statusMessages = new List<Status>();
|
||||||
_statusMessages.Add(new KeyValuePair<string, DateTime>(message, DateTime.Now + TimeSpan.FromSeconds(3.0f)));
|
var status = new Status { ID = _statusID++, Text = message, EndTime = DateTime.Now + TimeSpan.FromSeconds(3.0f) };
|
||||||
|
_statusMessages.Add(status);
|
||||||
if (_statusMessages.Count == 1)
|
if (_statusMessages.Count == 1)
|
||||||
UpdateStatusBar();
|
UpdateStatusBar();
|
||||||
|
return status.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a specific status message once it's not needed anymore,
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the message returned by <see cref="AddStatusMessage"/>.</param>
|
||||||
|
public void RemoveStatusMessage(int id)
|
||||||
|
{
|
||||||
|
if (_statusMessages == null || id == 0)
|
||||||
|
return;
|
||||||
|
for (var i = 0; i < _statusMessages.Count; i++)
|
||||||
|
{
|
||||||
|
if (_statusMessages[i].ID == id)
|
||||||
|
{
|
||||||
|
_statusMessages.RemoveAt(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool ProgressVisible
|
internal bool ProgressVisible
|
||||||
@@ -525,7 +555,7 @@ namespace FlaxEditor.Modules
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnUpdate()
|
public override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (_statusMessages != null && _statusMessages.Count > 0 && _statusMessages[0].Value - DateTime.Now < TimeSpan.Zero)
|
if (_statusMessages != null && _statusMessages.Count > 0 && _statusMessages[0].EndTime - DateTime.Now < TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
_statusMessages.RemoveAt(0);
|
_statusMessages.RemoveAt(0);
|
||||||
UpdateStatusBar();
|
UpdateStatusBar();
|
||||||
@@ -733,6 +763,16 @@ namespace FlaxEditor.Modules
|
|||||||
_menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
|
_menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
|
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
|
||||||
|
cm.AddSeparator();
|
||||||
|
var childMenu = cm.AddChildMenu("Open Product Local folder");
|
||||||
|
childMenu.ContextMenu.AddButton("Editor", () => FileSystem.ShowFileExplorer(Globals.ProductLocalFolder));
|
||||||
|
_menuToolsOpenLocalFolder = childMenu.ContextMenu.AddButton("Game", () =>
|
||||||
|
{
|
||||||
|
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
GameSettings settings = GameSettings.Load<GameSettings>();
|
||||||
|
string path = Path.Combine(localAppData, settings.CompanyName, settings.ProductName);
|
||||||
|
FileSystem.ShowFileExplorer(path);
|
||||||
|
});
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
MenuWindow = MainMenu.AddButton("Window");
|
MenuWindow = MainMenu.AddButton("Window");
|
||||||
@@ -774,9 +814,12 @@ namespace FlaxEditor.Modules
|
|||||||
private void InitWindowDecorations(RootControl mainWindow)
|
private void InitWindowDecorations(RootControl mainWindow)
|
||||||
{
|
{
|
||||||
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
|
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
|
||||||
var driver = Platform.DisplayServer;
|
string driver = string.Empty;
|
||||||
|
#if PLATFORM_LINUX
|
||||||
|
driver = LinuxPlatform.DisplayServer;
|
||||||
if (!string.IsNullOrEmpty(driver))
|
if (!string.IsNullOrEmpty(driver))
|
||||||
driver = $" ({driver})";
|
driver = $" ({driver})";
|
||||||
|
#endif
|
||||||
|
|
||||||
WindowDecorations = new MainWindowDecorations(mainWindow, !Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
|
WindowDecorations = new MainWindowDecorations(mainWindow, !Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
|
||||||
{
|
{
|
||||||
@@ -1084,6 +1127,10 @@ namespace FlaxEditor.Modules
|
|||||||
_menuToolsBuildNavMesh.Enabled = canEdit;
|
_menuToolsBuildNavMesh.Enabled = canEdit;
|
||||||
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
|
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
|
||||||
_menuToolsSetTheCurrentSceneViewAsDefault.Enabled = Level.ScenesCount > 0;
|
_menuToolsSetTheCurrentSceneViewAsDefault.Enabled = Level.ScenesCount > 0;
|
||||||
|
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
GameSettings settings = GameSettings.Load<GameSettings>();
|
||||||
|
string path = Path.Combine(localAppData, settings.CompanyName, settings.ProductName);
|
||||||
|
_menuToolsOpenLocalFolder.Enabled = Directory.Exists(path);
|
||||||
|
|
||||||
c.PerformLayout();
|
c.PerformLayout();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,10 +490,15 @@ namespace FlaxEditor.Modules
|
|||||||
Editor.LogWarning("Empty panel inside layout.");
|
Editor.LogWarning("Empty panel inside layout.");
|
||||||
p.RemoveIt();
|
p.RemoveIt();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.CollapseEmptyTabsProxy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.SelectTab(selectedTab);
|
panel.SelectTab(selectedTab);
|
||||||
|
panel.CollapseEmptyTabsProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SaveBounds(XmlWriter writer, Window win)
|
private static void SaveBounds(XmlWriter writer, Window win)
|
||||||
|
|||||||
@@ -387,6 +387,14 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Viewport"), EditorOrder(1760)]
|
[EditorDisplay("Viewport"), EditorOrder(1760)]
|
||||||
public InputBinding ToggleOrthographic = new InputBinding(KeyboardKeys.NumpadDecimal);
|
public InputBinding ToggleOrthographic = new InputBinding(KeyboardKeys.NumpadDecimal);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "G")]
|
||||||
|
[EditorDisplay("Viewport"), EditorOrder(1770)]
|
||||||
|
public InputBinding ToggleGameView = new InputBinding(KeyboardKeys.G);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "P")]
|
||||||
|
[EditorDisplay("Viewport"), EditorOrder(1770)]
|
||||||
|
public InputBinding ToggleNavMeshVisibility = new InputBinding(KeyboardKeys.P);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Debug Views
|
#region Debug Views
|
||||||
@@ -571,6 +579,10 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("View Flags"), EditorOrder(3260)]
|
[EditorDisplay("View Flags"), EditorOrder(3260)]
|
||||||
public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift);
|
public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
|
[EditorDisplay("View Flags"), EditorOrder(3270)]
|
||||||
|
public InputBinding Particles = new InputBinding(KeyboardKeys.None);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Interface
|
#region Interface
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user