222 Commits

Author SHA1 Message Date
7e72e856e1 Fix building ogg+vorbis on macOS
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-10-18 02:34:50 +03:00
2e78190bf0 Fix NvCloth compilation on Linux and macOS 2025-10-18 02:34:41 +03:00
03df23679f Fix PhysX compilation on Linux and macOS 2025-10-18 02:34:33 +03:00
c2cbf11e4d Fix python tool call on macOS for glslang 2025-10-18 02:34:22 +03:00
f4c3fb1c72 Fix building PhysX on Linux and macOS 2025-10-18 02:34:14 +03:00
5327529f38 Support building OpenAL from Git repository in other platforms 2025-10-18 02:34:04 +03:00
12f686262c Fix building curl on Linux 2025-10-18 02:33:54 +03:00
c76b9f206f Fix building Assimp on Linux
Versioned clang++ symlinks are not available on Arch
2025-10-18 02:33:44 +03:00
078485892f Add support for building dependencies with specific architecture 2025-10-18 02:33:22 +03:00
44b2db5d5d Fix CMake compatibility errors with dependencies 2025-10-18 02:19:57 +03:00
cc401f0316 Support Visual Studio 2026 as a generator for CMake dependencies 2025-10-18 02:19:57 +03:00
f52f3920cb Update SDL to 3.2.24 2025-10-18 02:19:56 +03:00
f99a244b8e Merge remote-tracking branch 'origin/master' into sdl_platform
# Conflicts:
#	Source/Editor/Windows/GameWindow.cs
2025-10-18 02:19:30 +03:00
Wojtek Figat
d93c32db9c Merge remote-tracking branch 'origin/1.11'
# Conflicts:
#	Source/Tools/Flax.Build/Deps/Downloader.cs
2025-10-16 14:07:49 +02:00
Wojtek Figat
08abdc159e Another ios build change to use dotnet 9 instead 2025-10-16 13:38:26 +02:00
Wojtek Figat
708b9c6767 Attempt to fix missing ios workload for .NET 8 2025-10-16 12:12:37 +02:00
Wojtek Figat
ed26a4c182 Fix moving character controller when displacement is zero 2025-10-16 11:34:43 +02:00
Wojtek Figat
a239984908 Add console logging for VSCode on Mac and Linux inside game projects 2025-10-16 10:47:41 +02:00
Wojtek Figat
fc3ea44c69 Update OpenAL on Mac/iOS 2025-10-16 10:40:08 +02:00
Wojtek Figat
fdecad0d29 Fix Vulkan crash on missing handle owner during binding 2025-10-16 10:39:50 +02:00
Wojtek Figat
c7437ed533 Fix OpenAL Soft building due to missing certs on a website 2025-10-16 10:39:36 +02:00
Wojtek Figat
dab44f5ceb Minor fixes 2025-10-16 10:20:51 +02:00
Wojtek Figat
c635d93b3c Fix more errors in Visject context menu regressions 2025-10-15 14:44:58 +02:00
Wojtek Figat
09fa3ce4be Minor changes 2025-10-14 15:07:40 +02:00
668a4dbb4d Merge remote-tracking branch 'origin/master' into sdl_platform 2025-10-14 01:09:26 +03:00
Wojtek Figat
e1b3429b4c Fix regression on game window defocus 2025-10-13 21:50:19 +02:00
Wojtek Figat
efa963be68 Fix editor error when prefab asset is unloaded 2025-10-13 21:45:31 +02:00
Wojtek Figat
e19be4c0c6 Merge branch 'xxSeys1-ColorValueBoxDisplayAlpha' 2025-10-13 20:53:22 +02:00
Wojtek Figat
2d5fdfef2f Merge branch 'ColorValueBoxDisplayAlpha' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-ColorValueBoxDisplayAlpha 2025-10-13 20:51:13 +02:00
Wojtek Figat
46ee6bc193 Merge branch 'xxSeys1-NicerOldNewEditorWarnings' 2025-10-13 20:50:17 +02:00
Wojtek Figat
a2ee2ec6ac Merge branch 'NicerOldNewEditorWarnings' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-NicerOldNewEditorWarnings 2025-10-13 20:50:13 +02:00
Wojtek Figat
2caaef02ad Merge branch 'Tryibion-fix-coll-data-delete-crash' 2025-10-13 20:49:37 +02:00
Chandler Cox
b62f331b08 Fix crash when deleting collision data. 2025-10-12 17:04:40 -05:00
Wojtek Figat
f7b306532b Merge branch 'GoaLitiuM-openal_pipewire_fixes' 2025-10-12 23:25:24 +02:00
Wojtek Figat
212abe7d90 Update OpenAL for Windows and Android
#3338
2025-10-12 23:25:17 +02:00
Wojtek Figat
7dfc37f652 Adjustments for #3338 2025-10-12 23:24:34 +02:00
Wojtek Figat
12decc3320 Merge branch 'openal_pipewire_fixes' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-openal_pipewire_fixes
# Conflicts:
#	Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs
2025-10-12 22:39:34 +02:00
Wojtek Figat
d7a528cdbc Update assets 2025-10-12 22:38:11 +02:00
Wojtek Figat
18364d2a8b Merge remote-tracking branch 'origin/1.11' 2025-10-12 21:50:19 +02:00
Saas
5a9eedfadb make old/ new editor dialog boxes nicer to read 2025-10-12 20:14:43 +02:00
Saas
be7871c292 use Render2D based solution rather than shader for alpha grid
https://github.com/FlaxEngine/FlaxEngine/pull/3281#issuecomment-3218049398
2025-10-12 16:50:31 +02:00
Wojtek Figat
abdeaa9354 Update build number 2025-10-11 00:17:41 +02:00
Wojtek Figat
d3389604b0 Update engine materials 2025-10-11 00:17:02 +02:00
Wojtek Figat
d426c5b0d9 Merge remote-tracking branch 'origin/master' into 1.11
# Conflicts:
#	Source/Engine/Physics/Colliders/Collider.h
2025-10-11 00:16:10 +02:00
Wojtek Figat
8da0d2c4ce Merge branch 'xxSeys1-IndustryStandardSettingsShortcut' 2025-10-10 08:31:40 +02:00
Wojtek Figat
20f576783b Merge branch 'IndustryStandardSettingsShortcut' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-IndustryStandardSettingsShortcut 2025-10-10 08:31:32 +02:00
Wojtek Figat
2bf62cc54f Add GPUDevice.VideoOutputs with a list of attached monitors 2025-10-09 15:13:04 +02:00
Wojtek Figat
ef2c551cee Fix build 2025-10-08 23:24:15 +02:00
Wojtek Figat
65cf59642c Fix changing Rigid Body center of mass offset
#2325 #3247
2025-10-08 22:16:46 +02:00
Wojtek Figat
e2fc8a6283 Add drawing RigidBody center of mass and attached colliders
#2325 #3247
2025-10-08 22:16:16 +02:00
Wojtek Figat
73976f3ed9 Fix box collider to properly draw small bounds 2025-10-08 22:08:34 +02:00
Wojtek Figat
7ab6bafe39 Fix crash when saving empty json string 2025-10-08 22:02:05 +02:00
Wojtek Figat
deb2ad7c8f Fix font hit test on multi-line text past the line end character
#3503
2025-10-08 16:36:34 +02:00
Wojtek Figat
cd7fc3242e Merge branch 'ZaPx64-ZaPx64-texture-asset-save-fix' 2025-10-08 09:14:59 +02:00
Wojtek Figat
31a0a77e7c Merge branch 'ZaPx64-texture-asset-save-fix' of https://github.com/ZaPx64/FlaxEngine into ZaPx64-ZaPx64-texture-asset-save-fix 2025-10-08 09:14:54 +02:00
Wojtek Figat
f0ec4a901a Merge branch 'xxSeys1-StraightenConnectionFix' 2025-10-08 09:13:45 +02:00
Wojtek Figat
8cb67f017a Fix PlayStation build regression 2025-10-07 18:23:53 +02:00
Wojtek Figat
7b643e9685 Fix volumetric fog particles drawing regression 2025-10-07 18:23:39 +02:00
Wojtek Figat
39803ce6b2 Add **render layer mask to decals**
#967 #3080
2025-10-07 18:23:03 +02:00
Wojtek Figat
2f1f380062 Add new scene textures SceneStencil and ObjectLayer to sample Stencil buffer 2025-10-07 18:10:14 +02:00
Wojtek Figat
f8dbf363b6 Fix crash on Android when loading mesh with SDF data 2025-10-07 18:09:18 +02:00
Wojtek Figat
fc1451254d Fix missing terrain debug shapes drawing when only in a view 2025-10-07 18:08:51 +02:00
Wojtek Figat
d3c54e590a Fix quad overdraw debug drawing regression 2025-10-07 18:08:32 +02:00
Wojtek Figat
361fc3ecfb Add stencil buffer usage with object layer information
#3080 #967
2025-10-07 18:07:23 +02:00
ZaPx64
3682159da6 Fix Save() failing on virtual texture asset 2025-10-05 09:20:54 +02:00
Saas
e9f83f77bb fix "Straighten Connections" to actually straighten all connections 2025-10-04 14:03:02 +02:00
Wojtek Figat
823ed247d2 Merge remote-tracking branch 'origin/master' into 1.11
# Conflicts:
#	Source/Engine/Level/Actors/Sky.cpp
2025-10-03 22:37:32 +02:00
Wojtek Figat
8f3b80492e Fix terrain physics error on end play when it's disabled
#3590 #3603
2025-10-03 22:30:44 +02:00
Wojtek Figat
c61c013517 Merge branch 'xxSeys1-StrokeMyEgo' 2025-10-03 22:22:11 +02:00
Wojtek Figat
a2170ffd8a Merge branch 'StrokeMyEgo' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-StrokeMyEgo 2025-10-03 22:22:07 +02:00
Wojtek Figat
4f1f77fb32 Simplify code of EditorViewport to access editor instance 2025-10-03 22:21:11 +02:00
Wojtek Figat
6ae370f8fc Fix camera cut flag in rendering to not trigger on origin change for smother visuals 2025-10-03 22:20:58 +02:00
Saas
da5c8555e5 add myself to list of Flax authors lol
Mafi said I should do this :)
2025-10-03 21:16:28 +02:00
Saas
c4c7ee941f add industry standard shortcut for editor settings 2025-10-03 14:46:43 +02:00
Wojtek Figat
4f45b3c1d0 Fix missing root motion copy when using input skeleton pose (eg. IK node)
#3445
2025-10-03 11:33:01 +02:00
Wojtek Figat
4c640b915f Fix CheckBox to display check state when created in game without editor icon atlas
#3705
2025-10-03 11:25:25 +02:00
Wojtek Figat
1f3f1ea67e Fix Blend Poses nodes to smoothly blend back when transition goes back
#3595
2025-10-03 10:52:01 +02:00
Wojtek Figat
60c19303f6 Fix duplicating splines with parents
#3531
2025-10-02 23:31:03 +02:00
Wojtek Figat
adcfc50218 Fix stack overflow exception in shader graph recursion to be detected
#3706
2025-10-02 20:49:50 +02:00
Wojtek Figat
9b812ec34a Fix BoundingFrustum::GetPlane in C++ to match C# version (and doc comment) 2025-10-02 18:48:32 +02:00
Wojtek Figat
7e1ac5e167 Fix sky rendering in ortho and oblique projection
#3448
2025-10-02 18:48:14 +02:00
Wojtek Figat
028b5fedec Use right-click only on GPUTextureEditor context menu 2025-09-30 23:37:15 +02:00
Wojtek Figat
9cc2c1da40 Fix terrain exporting to properly calculate size and sample positions
#3534
2025-09-30 22:58:08 +02:00
Wojtek Figat
93219793d5 Merge remote-tracking branch 'origin/master' into 1.11 2025-09-30 18:26:14 +02:00
Wojtek Figat
32f2ef3f06 Fix Android compilation 2025-09-30 18:26:10 +02:00
Wojtek Figat
5ed8564293 Merge branch 'xxSeys1-visjectPanOnNode' 2025-09-30 16:08:37 +02:00
Wojtek Figat
7c87ade12b Merge branch 'visjectPanOnNode' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-visjectPanOnNode 2025-09-30 15:51:17 +02:00
Wojtek Figat
7f87678282 Merge branch 'xxSeys1-IssueTemplateFix' 2025-09-30 15:49:18 +02:00
Wojtek Figat
e429d29d17 Merge branch 'IssueTemplateFix' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-IssueTemplateFix 2025-09-30 15:49:11 +02:00
Wojtek Figat
086a49f45d Fix deadlock when updating Text Render layout during scene rendering 2025-09-30 15:46:06 +02:00
Wojtek Figat
c46e1164d6 Add hot-reload support for material feature template sources on material generation 2025-09-30 15:45:45 +02:00
Wojtek Figat
2a5898c1de Fix regression from #3342 to use existing time as unscaled to match previous content 2025-09-30 15:45:24 +02:00
Wojtek Figat
f09d6aa0eb Fix fog rendering bug on d3d11/d3d10 2025-09-30 15:44:34 +02:00
Wojtek Figat
0848f1fa83 Refactor specular lighting to properly map specular as reflectance in BRDF
Reference: https://google.github.io/filament/Filament.md.html

#1492
2025-09-30 15:43:55 +02:00
Wojtek Figat
537d8b57ca Revert "Merge branch 'NoClearSearchboxesWhenStuffHappens' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-NoClearSearchboxesWhenStuffHappens"
This reverts commit 1186833b2d, reversing
changes made to bb180b0f59.

#3687 #3701
2025-09-26 22:25:49 +02:00
Wojtek Figat
02c5ad3fa4 Fix particles to support any amount of contexts drawings 2025-09-25 18:38:46 +02:00
Wojtek Figat
41e851298d Add new PreIntegratedGF with 80% smaller but more accurate data
Update old generation code, use R16G16_UNorm format instead of R11G11B10, skip mips and reduce Y axis to 32 pixels.

#1492
2025-09-25 17:35:10 +02:00
Saas
4a3fb41035 further fixes and make some stuff a bit nicer 2025-09-25 13:32:21 +02:00
Wojtek Figat
d57eec3403 Bump up materials after merge 2025-09-24 18:26:33 +02:00
Wojtek Figat
87e2c4c4d5 Merge remote-tracking branch 'origin/master' into 1.11
# Conflicts:
#	Content/Editor/DebugMaterials/DDGIDebugProbes.flax
#	Source/Editor/Windows/OutputLogWindow.cs
#	Source/Engine/Level/Actor.cpp
2025-09-24 18:18:27 +02:00
Saas
797cb3c3f2 fix 1.10 becoming 1.1 and some spelling issue in issue template 2025-09-23 20:56:43 +02:00
Wojtek Figat
47670251ef Merge branch 'Tryibion-issue-template' 2025-09-23 17:21:34 +02:00
Wojtek Figat
cf1ef91246 Merge branch 'issue-template' of https://github.com/Tryibion/FlaxEngine into Tryibion-issue-template 2025-09-23 17:21:30 +02:00
Wojtek Figat
7060cb5696 Fix UI Brush editing in prefab regression from a471861e92
#3694
2025-09-23 17:20:18 +02:00
Wojtek Figat
c449833d35 Merge branch 'Tryibion-audio-events' 2025-09-23 17:07:22 +02:00
Wojtek Figat
284aeca51a Merge branch 'audio-events' of https://github.com/Tryibion/FlaxEngine into Tryibion-audio-events 2025-09-23 17:07:18 +02:00
Wojtek Figat
d8f7199c11 Fix importing emissive, roughness, metalness and wireframe properties of materials with Assimp
#3418
2025-09-23 15:42:49 +02:00
Wojtek Figat
dc05bbbbcd Merge branch 'IceReaper-feature/create_project' 2025-09-22 22:45:50 +02:00
Wojtek Figat
3fcc9ed01f Merge branch 'feature/create_project' of https://github.com/IceReaper/FlaxEngine into IceReaper-feature/create_project 2025-09-22 22:32:43 +02:00
Wojtek Figat
70ba750a5e Fix code #3511 2025-09-22 22:31:23 +02:00
Wojtek Figat
50271199ac Merge branch 'xxSeys1-moveVisjectConnection' 2025-09-22 22:30:32 +02:00
Wojtek Figat
d1a99c9396 Merge branch 'moveVisjectConnection' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-moveVisjectConnection
# Conflicts:
#	Source/Editor/Surface/VisjectSurface.cs
2025-09-22 22:30:26 +02:00
Chandler Cox
4ae3d57adc Resolve code suggestions 2025-09-22 11:32:24 -05:00
Wojtek Figat
99b9967806 Merge branch 'xxSeys1-ViewportIconsMoreCustomization' 2025-09-22 18:10:38 +02:00
Wojtek Figat
2f7e84253a Merge branch 'ViewportIconsMoreCustomization' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-ViewportIconsMoreCustomization 2025-09-22 18:10:33 +02:00
Wojtek Figat
2f55cb938f Merge branch 'xxSeys1-commandSuggestionImprovements' 2025-09-22 18:08:30 +02:00
Wojtek Figat
a86661a855 Merge branch 'commandSuggestionImprovements' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-commandSuggestionImprovements 2025-09-22 18:06:55 +02:00
Wojtek Figat
a68ce6633a Merge branch 'Tryibion-vs-code-plugin-organize' 2025-09-22 18:02:52 +02:00
Wojtek Figat
5d57afe3aa Merge branch 'vs-code-plugin-organize' of https://github.com/Tryibion/FlaxEngine into Tryibion-vs-code-plugin-organize 2025-09-22 18:02:00 +02:00
Wojtek Figat
6705138247 Merge branch 'xxSeys1-SmallVehicleImprovements' 2025-09-22 16:18:17 +02:00
Wojtek Figat
276caf771c Merge branch 'SmallVehicleImprovements' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-SmallVehicleImprovements
# Conflicts:
#	Source/Engine/Physics/Actors/WheeledVehicle.h
2025-09-22 16:18:12 +02:00
Wojtek Figat
5eea5a72c9 Fix particle material compilation error when using position offset
#3661
2025-09-22 11:44:11 +02:00
Wojtek Figat
e9a7b1c8eb Fix using enums as Scene Animation Event parameters
#3554
2025-09-22 10:22:32 +02:00
Wojtek Figat
a151c78412 Fix loading projects that have similar path to engine folder
#3565
2025-09-22 08:42:16 +02:00
Wojtek Figat
5f1e905e8f Fix crash when importing model as prefab and handle duplicated object names
#3558
2025-09-21 22:52:57 +02:00
Wojtek Figat
a0f764a774 Add skybox rotation feature
#3592
2025-09-21 21:58:03 +02:00
Wojtek Figat
7da5ce3ed4 Merge branch 'xxSeys1-NoClearSearchboxesWhenStuffHappens' 2025-09-21 21:06:21 +02:00
Wojtek Figat
1186833b2d Merge branch 'NoClearSearchboxesWhenStuffHappens' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-NoClearSearchboxesWhenStuffHappens 2025-09-21 21:06:16 +02:00
Wojtek Figat
bb180b0f59 Merge branch 'Tryibion-fix-physics-attach-rigid' 2025-09-21 21:04:59 +02:00
Wojtek Figat
5d1c79929a Merge branch 'fix-physics-attach-rigid' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-physics-attach-rigid 2025-09-21 21:04:56 +02:00
Wojtek Figat
3f5a4cc4c9 Merge branch 'Tryibion-fix-dup&remove' 2025-09-21 21:02:22 +02:00
Wojtek Figat
62fd8ac967 Merge branch 'fix-dup&remove' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-dup&remove 2025-09-21 21:02:17 +02:00
Wojtek Figat
d904b92f2e Merge branch 'xxSeys1-LessCreateScriptItems' 2025-09-21 21:01:36 +02:00
Wojtek Figat
87e2b76ffa Merge branch 'LessCreateScriptItems' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-LessCreateScriptItems 2025-09-21 21:01:33 +02:00
Wojtek Figat
c5e11aed15 Merge branch 'xxSeys1-WidgetCreateFilterControlTypes' 2025-09-21 21:00:27 +02:00
Wojtek Figat
85d61b334b Merge branch 'WidgetCreateFilterControlTypes' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-WidgetCreateFilterControlTypes 2025-09-21 21:00:11 +02:00
Wojtek Figat
26e94f6f8e Refactor material instance to not override all public parameters by default (need explicit set)
#3444
2025-09-21 20:59:25 +02:00
Wojtek Figat
902744a0ce Fix model import scale on nodes that could be applied multiple times on the same mesh
#3562
2025-09-21 15:08:35 +02:00
Wojtek Figat
1c581bceaf Fix sun shadows when direction is perfectly vertical
#3614
2025-09-20 23:52:04 +02:00
Wojtek Figat
9cc44825c6 Update engine materials 92f4327fc2 2025-09-20 00:14:51 +02:00
Wojtek Figat
92f4327fc2 Fix missing volumetric fog affecting transparent materials
#3436
2025-09-20 00:13:52 +02:00
Wojtek Figat
47711ec5be Fix Volumetric Fog flicker on camera cuts
#3443
2025-09-19 23:10:03 +02:00
Chandler Cox
d1fbc66cb9 Fix not attaching updated collision data to rigid body. 2025-09-19 15:58:22 -05:00
Saas
7183a3306e fix typo 2025-09-19 16:57:50 +02:00
Saas
fd191f7ffb don't clear content panel folder- and scene tree search box on script reload and enter/ exit play 2025-09-18 23:24:10 +02:00
Saas
2604d58687 no more Linq 2025-09-18 17:37:04 +02:00
Chandler Cox
01d1d634c2 Fix other missing duplicate. 2025-09-16 17:43:55 -05:00
Chandler Cox
c7e403661d Dont allow remove and duplicate options for non-resizing collections. 2025-09-16 17:42:24 -05:00
Saas
1196db6d17 check if control is control meant for gui editor use 2025-09-16 22:54:57 +02:00
Saas
553a007508 Revert "hide TrackLabel control in editor"
This reverts commit 364a523375.
2025-09-16 22:14:22 +02:00
Saas
de2ee36529 fix naming lol 2025-09-16 22:07:42 +02:00
Saas
eea44ac897 remove search query highlights showing on create new script item 2025-09-16 22:06:49 +02:00
Saas
c124713e99 remove create new script items when searchbox is cleared 2025-09-16 22:05:28 +02:00
Saas
364a523375 hide TrackLabel control in editor 2025-09-16 22:04:24 +02:00
Wojtek Figat
afdd264e63 Fix compilation of Editor in Release mode 2025-09-16 16:34:58 +02:00
Wojtek Figat
8ec54f7b1c Merge branch 'cNori-Custom-editor-for-GPUTextures' 2025-09-16 00:16:10 +02:00
Wojtek Figat
521518bde4 Add hack to use GPUTextureEditor on ref pickers 2025-09-16 00:15:58 +02:00
Wojtek Figat
56077a268a SImplify and cleanup GPUTexture editor #3452 #3194 2025-09-16 00:15:48 +02:00
Wojtek Figat
a0ca000793 Merge branch 'Custom-editor-for-GPUTextures' of https://github.com/cNori/FlaxEngineFork into cNori-Custom-editor-for-GPUTextures 2025-09-15 18:08:02 +02:00
Wojtek Figat
ae4ae7a638 Fix rich textbox vertical alignment
#3502
2025-09-15 15:17:18 +02:00
Wojtek Figat
e2a4c8ab03 Merge branch 'Tryibion-fix-viewdistance-light' 2025-09-15 14:14:04 +02:00
Chandler Cox
7a40722964 Fix view distance light property from affecting brightness all of the time. 2025-09-14 17:51:27 -05:00
Wojtek Figat
1de8909d05 Merge branch 'Tryibion-prefab-viewport-scaling' 2025-09-14 23:59:45 +02:00
Wojtek Figat
9749487e24 Move prefab and game UI size context menu to shared UI Module
#3571
2025-09-14 23:59:40 +02:00
Wojtek Figat
55968a8ddc Merge branch 'prefab-viewport-scaling' of https://github.com/Tryibion/FlaxEngine into Tryibion-prefab-viewport-scaling 2025-09-14 23:11:59 +02:00
Wojtek Figat
e325b190ea Merge branch 'xxSeys1-disabledGizmoBrightness' 2025-09-14 22:01:18 +02:00
Wojtek Figat
ada6b9140f Minor adjustments for #3411 2025-09-14 22:00:57 +02:00
Wojtek Figat
5582579173 Merge branch 'disabledGizmoBrightness' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-disabledGizmoBrightness 2025-09-14 21:45:57 +02:00
Wojtek Figat
88773e71e5 Fix warning when cloning actor from prefab that is not a root
#3578
2025-09-14 14:25:19 +02:00
Wojtek Figat
9e1f488f22 Fix prefab window to use UI Mode for empty UI Control prefab
#3574
2025-09-13 14:41:11 +02:00
Wojtek Figat
a471861e92 Fix editing UI Brush in prefabs
#3501
2025-09-12 23:15:13 +02:00
Wojtek Figat
3d182c89f3 Add MaterialShader::BindParameters to usable in game scripts
#3668
2025-09-12 18:04:01 +02:00
Wojtek Figat
e3810a9938 Merge branch 'GoaLitiuM-vs2026' 2025-09-12 18:02:07 +02:00
Wojtek Figat
f323fdb592 Add and use Max Mesh Position Error to Build Settings for automatic mesh vertex positions storage 2025-09-12 17:53:14 +02:00
f0dea9d528 Add support for Visual Studio 2026 and v145 MSVC toolset 2025-09-10 20:05:56 +03:00
Wojtek Figat
b537a80031 Fix regression in lights/shadows setup from 1a88fefd76 2025-09-09 23:53:28 +02:00
Wojtek Figat
5e52bf6469 Fix missing code from 80de56f469 2025-09-09 23:21:10 +02:00
Wojtek Figat
8482f93a0f Merge remote-tracking branch 'origin/1.11' into 1.11 2025-09-09 22:58:34 +02:00
Wojtek Figat
64c62f269c Optimize D3D12 with D3D12_HEAP_FLAG_CREATE_NOT_ZEROED in some cases 2025-09-09 22:54:37 +02:00
Wojtek Figat
19d0d3b683 Remove system lockers during asset loads or saving (only unload needs it) 2025-09-09 15:26:27 +02:00
Wojtek Figat
1f56c75821 Minor fixes 2025-09-09 15:26:03 +02:00
Wojtek Figat
64e127a47a Fix crashes of scripting backend on Android 2025-09-09 15:25:24 +02:00
Wojtek Figat
8921cf5156 Add label/button text to string convertion for better debugging 2025-09-09 10:42:10 +02:00
Wojtek Figat
24e088fc08 Fix compilation warnings 2025-09-09 10:23:07 +02:00
Wojtek Figat
14a69a11df Add Android native crashes caching 2025-09-07 23:50:41 +02:00
Chandler Cox
e27880c1e6 Make plugins into their own folders in VSCode. Order VSCode plugin folders with Engine at the bottom. 2025-08-02 09:28:49 -05:00
Chandler Cox
6f15ef7690 Fix location of clip start call. 2025-08-01 15:15:54 -05:00
Chandler Cox
0e3a22faa0 Fix spelling in comment. 2025-08-01 15:11:06 -05:00
Chandler Cox
0dc1e04c89 Add slider to audio debug editor for selecting time. 2025-08-01 15:07:49 -05:00
Chandler Cox
5c7712daad Add audio clip started and finished events to audio source 2025-08-01 15:07:25 -05:00
Chandler Cox
52b64540ab Add extra index guard logic 2025-06-28 10:46:11 -05:00
Chandler Cox
b9cfd054c1 Remove unused variable 2025-06-27 21:38:10 -05:00
Chandler Cox
53d4ea51af Add prefab UI viewport scaling. 2025-06-27 21:18:53 -05:00
xxSeys1
a4d3ede368 fix context menu on reroute node 2025-06-15 02:08:47 +02:00
xxSeys1
92edb996f2 properly handle connecting to a box that already has a connection 2025-06-14 17:20:28 +02:00
xxSeys1
2e0c35e6e4 fix out of range error when searching visject cm 2025-06-14 01:04:35 +02:00
xxSeys1
baba151d8a fix context menu 2025-06-14 00:54:16 +02:00
xxSeys1
b44d4107c0 fixes 2025-06-13 22:25:02 +02:00
xxSeys1
f40c67ddf0 add support to move visject socket connections 2025-06-13 22:05:57 +02:00
xxSeys1
ec154b4998 remove unnecessary returns xml doc comment 2025-06-12 19:31:32 +02:00
xxSeys1
6997cbeb47 add options for viewport icons 2025-06-11 13:08:59 +02:00
xxSeys1
c4130aa20f fix and improve show all commands on " " behavior 2025-06-04 15:23:42 +02:00
xxSeys1
c9fe9213b3 add showing all commands if prompt is whitespace(s) 2025-06-02 23:25:50 +02:00
xxSeys1
608839b6a5 set width of command suggestions based on longest command 2025-06-02 22:33:22 +02:00
Norite SC
f71bdd0962 Create GPUTextureEditor.cs 2025-05-13 01:13:16 +02:00
xxSeys1
47a6da9e40 add editor option for disabled transform gizmo brightness 2025-04-27 15:56:34 +02:00
Chandler Cox
40dae18b76 Add new issue and request templates. 2025-04-24 18:48:29 -05:00
fc96b248cb Ignore invalid VelocityChanged velocity values in audio backend 2025-04-05 20:17:33 +03:00
36c1909111 Build OpenAL with PipeWire backend enabled 2025-04-05 20:17:32 +03:00
643fe639e5 Update OpenAL to 1.24.3 2025-04-05 20:17:32 +03:00
78dffc9ad1 Add override for building CMake project with custom configuration 2025-04-05 20:17:32 +03:00
xxSeys1
1dfd717093 serialize display info and color 2025-04-02 23:38:04 +02:00
xxSeys1
68ef6f08c6 minor style fixes 2025-04-02 19:40:27 +02:00
xxSeys1
a0b80c6096 add getters for more commonly used vehicle fields 2025-04-02 19:29:11 +02:00
xxSeys1
59ac8a3f60 move anti roll bars into Vehicle display group 2025-04-02 19:21:24 +02:00
xxSeys1
dd281bbca8 add wheel information debug draw 2025-04-02 19:12:36 +02:00
xxSeys1
2e48be97b6 add getter for steering 2025-04-02 17:24:13 +02:00
Andre Mohren
0b7550e5ca Implement creation of new projects from within the editor gui. 2025-04-02 15:10:11 +02:00
xxSeys1
051d363358 add alpha grid background 2025-03-14 15:51:36 +01:00
xxSeys1
9b495bbc68 improve how ColorValueBoxes draw transparent colors 2025-03-13 17:18:11 +01:00
xxSeys1
e665cc7500 add safe margin
4 pixels seemed a bit much, smaller adjustments could lead to the menu still showing
2024-09-16 15:43:46 +02:00
xxSeys1
0a516ac98d make it possible to pan editor when rmb down on node 2024-09-14 15:33:07 +02:00
334 changed files with 5585 additions and 2736 deletions

42
.github/ISSUE_TEMPLATE/1-bug.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please attach any minimal reproduction projects!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the bug and what you expected to happen.
validations:
required: true
- type: textarea
id: steps-area
attributes:
label: Steps to reproduce
description: Please provide reproduction steps if possible.
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of Flax are you running?
options:
- '1.8'
- '1.9'
- '1.10'
- '1.11'
- master branch
default: 2
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View File

@@ -0,0 +1,22 @@
name: Feature Request
description: File a feature request.
title: "[Request]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out a feature request!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the feature!
validations:
required: true
- type: textarea
id: benefits-area
attributes:
label: Benefits
description: Please provide what benefits this feature would provide to the engine!
validations:
required: true

View File

@@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Setup .NET Workload
run: |
dotnet workload install ios
@@ -33,4 +33,4 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=8 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=9 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame

BIN
Content/Editor/Camera/M_Camera.flax (Stored with Git LFS)

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/Editor/DefaultFontMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Gizmo/Material.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialWire.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Highlight Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Icons/IconsMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@@ -6,6 +6,7 @@
@3
#include "./Flax/Common.hlsl"
#include "./Flax/Stencil.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
@7
@@ -14,10 +15,13 @@ META_CB_BEGIN(0, Data)
float4x4 WorldMatrix;
float4x4 InvWorld;
float4x4 SvPositionToWorld;
float3 Padding0;
uint RenderLayersMask;
@1META_CB_END
// Use depth buffer for per-pixel decal layering
Texture2D DepthBuffer : register(t0);
Texture2D<uint2> StencilBuffer : register(t1);
// Material shader resources
@2
@@ -200,6 +204,14 @@ void PS_Decal(
#endif
)
{
// Stencil masking
uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy));
if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0)
{
clip(-1);
return;
}
float2 screenUV = SvPosition.xy * ScreenSize.zw;
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;

View File

@@ -27,6 +27,7 @@ TextureCube EnvProbe : register(t__SRV__);
TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__);
@4// Forward Shading: Utilities
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
LightData GetDirectionalLight() { return DirectionalLight; }
@@ -151,7 +152,25 @@ void PS_Forward(
#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Calculate exponential height fog
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
#if DIRECTX && FEATURE_LEVEL < FEATURE_LEVEL_SM6
// TODO: fix D3D11/D3D10 bug with incorrect distance
float fogSceneDistance = distance(materialInput.WorldPosition, ViewPos);
#else
float fogSceneDistance = gBuffer.ViewPos.z;
#endif
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance);
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
{
// Sample volumetric fog and mix it in
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float3 viewVector = materialInput.WorldPosition - ViewPos;
float sceneDepth = length(viewVector);
float depthSlice = sceneDepth / ExponentialHeightFog.VolumetricFogMaxDistance;
float3 volumeUV = float3(screenUV, depthSlice);
float4 volumetricFog = VolumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0);
fog = CombineVolumetricFog(fog, volumetricFog);
}
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE

View File

@@ -21,7 +21,7 @@ float4 ViewInfo;
float4 ScreenSize;
float4 ViewSize;
float3 ViewPadding0;
float UnscaledTimeParam;
float ScaledTimeParam;
@1META_CB_END
// Shader resources

View File

@@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
materialInput.TBN = output.TBN;
materialInput.TwoSidedSign = 1;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = Position;
materialInput.PreSkinnedPosition = position;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
materialInput.InstanceOrigin = output.InstanceOrigin;
materialInput.InstanceParams = output.InstanceParams;

View File

@@ -20,7 +20,7 @@ float4 ScreenSize;
float4 TemporalAAJitter;
float4x4 InverseViewProjectionMatrix;
float3 ViewPadding0;
float UnscaledTimeParam;
float ScaledTimeParam;
@1META_CB_END
// Shader resources

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/SpriteMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/TexturePreviewMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Wires Debug Material.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Engine/DefaultMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultRadialMenu.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultTerrainMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SingleColorMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SkyboxMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Shaders/Fog.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Reflections.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/SSR.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Sky.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 11,
"Revision": 0,
"Build": 6800
"Build": 6801
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",

View File

@@ -1,19 +0,0 @@
<!-- Please search existing issues for potential duplicates before filing yours:
https://github.com/flaxengine/FlaxEngine/issues?q=is%3Aissue
-->
**Issue description:**
<!-- What happened, and what was expected. -->
<!-- Log file, can be found in the project directory's `Logs` folder (optional) -->
**Steps to reproduce:**
<!-- Enter minimal reproduction steps if available. -->
**Minimal reproduction project:**
<!-- Recommended as it greatly speeds up debugging. Drag and drop a zip archive to upload it. -->
**Flax version:**
<!-- Specify version number. -->

View File

@@ -117,7 +117,8 @@ namespace FlaxEditor.Content.Create
private static bool IsValid(Type type)
{
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
var controlTypes = Editor.Instance.CodeEditing.Controls.Get();
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type));
}
}

View File

@@ -87,8 +87,11 @@ namespace FlaxEditor.CustomEditors
var targetTypeType = TypeUtils.GetType(targetType);
if (canUseRefPicker)
{
// TODO: add generic way of CustomEditor for ref pickers (use it on AssetRefEditor/GPUTextureEditor/...)
if (typeof(Asset).IsAssignableFrom(targetTypeType))
return new AssetRefEditor();
if (typeof(GPUTexture).IsAssignableFrom(targetTypeType))
return new GPUTextureEditor();
if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType))
return new FlaxObjectRefEditor();
}

View File

@@ -13,6 +13,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
public class AudioSourceEditor : ActorEditor
{
private Label _infoLabel;
private Slider _slider;
private AudioSource.States _slideStartState;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
@@ -28,6 +30,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
// Play back slider
var sliderElement = playbackGroup.CustomContainer<Slider>();
_slider = sliderElement.CustomControl;
_slider.ThumbSize = new Float2(_slider.ThumbSize.X * 0.5f, _slider.ThumbSize.Y);
_slider.SlidingStart += OnSlidingStart;
_slider.SlidingEnd += OnSlidingEnd;
var grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl;
gridControl.ClipChildren = false;
@@ -40,6 +49,38 @@ namespace FlaxEditor.CustomEditors.Dedicated
}
}
private void OnSlidingEnd()
{
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
switch (_slideStartState)
{
case AudioSource.States.Playing:
audioSource.Play();
break;
case AudioSource.States.Paused:
case AudioSource.States.Stopped:
audioSource.Pause();
break;
default: break;
}
}
}
}
private void OnSlidingStart()
{
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
_slideStartState = audioSource.State;
}
}
}
/// <inheritdoc />
public override void Refresh()
{
@@ -51,7 +92,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n";
_slider.Maximum = audioSource.Clip.Length;
_slider.Minimum = 0;
if (_slider.IsSliding)
{
if (audioSource.State != AudioSource.States.Playing)
{
// Play to move slider correctly
audioSource.Play();
audioSource.Time = _slider.Value;
}
else
{
audioSource.Time = _slider.Value;
}
}
else
{
_slider.Value = audioSource.Time;
}
}
}
_infoLabel.Text = text;
}

View File

@@ -0,0 +1,68 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Basic editor/viewer for <see cref="GPUTexture"/>.
/// </summary>
[CustomEditor(typeof(GPUTexture)), DefaultEditor]
public class GPUTextureEditor : CustomEditor
{
private Image _image;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
_image = new Image
{
Brush = new GPUTextureBrush(),
Size = new Float2(200, 100),
Parent = layout.ContainerControl,
};
_image.Clicked += OnImageClicked;
}
private void OnImageClicked(Image image, MouseButton button)
{
var texture = Values[0] as GPUTexture;
if (!texture || button != MouseButton.Right)
return;
var menu = new ContextMenu();
menu.AddButton("Save...", () => Screenshot.Capture(Values[0] as GPUTexture));
menu.AddButton("Enlarge", () => _image.Size *= 2);
menu.AddButton("Shrink", () => _image.Size /= 2).Enabled = _image.Height > 32;
var location = image.PointFromScreen(Input.MouseScreenPosition);
menu.Show(image, location);
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
var texture = Values[0] as GPUTexture;
((GPUTextureBrush)_image.Brush).Texture = texture;
if (texture)
{
var desc = texture.Description;
#if BUILD_RELEASE
var name = string.Empty;
#else
var name = texture.Name;
#endif
_image.TooltipText = $"{name}\nType: {texture.ResourceType}\nSize: {desc.Width}x{desc.Height}\nFormat: {desc.Format}\nMemory: {Utilities.Utils.FormatBytesCount(texture.MemoryUsage)}";
}
else
{
_image.TooltipText = "None";
}
}
}
}

View File

@@ -36,6 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
ScriptName = scriptName;
TooltipText = "Create a new script";
DrawHighlights = false;
}
}
@@ -70,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
_addScriptsButton = new Button
{
TooltipText = "Add new scripts to the actor",
TooltipText = "Add new scripts to the actor.",
AnchorPreset = AnchorPresets.MiddleCenter,
Text = buttonText,
Parent = this,
@@ -114,7 +115,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
cm.TextChanged += text =>
{
if (!IsValidScriptName(text))
{
// Remove NewScriptItems
List<Control> newScriptItems = cm.ItemsPanel.Children.FindAll(c => c is NewScriptItem);
foreach (var item in newScriptItems)
{
cm.ItemsPanel.RemoveChild(item);
}
return;
}
if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem))
{
// If there are no visible items, that means the search failed so we can find the create script button or create one if it's the first time
@@ -876,7 +886,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Add drag button to the group
var scriptDrag = new DragImage
{
TooltipText = "Script reference",
TooltipText = "Script reference.",
AutoFocus = true,
IsScrollable = false,
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,

View File

@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
b = menu.AddButton("Paste", linkedEditor.Paste);
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
@@ -407,7 +407,7 @@ namespace FlaxEditor.CustomEditors.Editors
menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
@@ -422,7 +422,8 @@ namespace FlaxEditor.CustomEditors.Editors
moveDownButton.Enabled = Index + 1 < Editor.Count;
}
menu.AddButton("Remove", OnRemoveClicked);
b = menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly && Editor._canResize;
menu.Show(panel, location);
}

View File

@@ -3,6 +3,7 @@
using System;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.Utilities;
namespace FlaxEditor.CustomEditors.Editors
@@ -81,9 +82,13 @@ namespace FlaxEditor.CustomEditors.Editors
private OptionType[] _options;
private ScriptType _type;
private Elements.PropertiesListElement _typeItem;
private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
/// <inheritdoc />
public override bool RevertValueWithChildren => false; // Always revert value for a whole object
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
@@ -98,7 +103,8 @@ namespace FlaxEditor.CustomEditors.Editors
_type = type;
// Type
var typeEditor = layout.ComboBox(TypeComboBoxName, "Type of the object value. Use it to change the object.");
_typeItem = layout.AddPropertyItem(TypeComboBoxName, "Type of the object value. Use it to change the object.");
var typeEditor = _typeItem.ComboBox();
for (int i = 0; i < _options.Length; i++)
{
typeEditor.ComboBox.AddItem(_options[i].Name);
@@ -126,6 +132,8 @@ namespace FlaxEditor.CustomEditors.Editors
// Value
var values = new CustomValueContainer(type, (instance, index) => instance);
if (Values.HasReferenceValue)
values.SetReferenceValue(Values.ReferenceValue);
values.AddRange(Values);
var editor = CustomEditorsUtil.CreateEditor(type);
var style = editor.Style;
@@ -170,6 +178,12 @@ namespace FlaxEditor.CustomEditors.Editors
{
base.Refresh();
// Show prefab diff when reference value type is different
var color = Color.Transparent;
if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0]?.GetType() != Values.ReferenceValue?.GetType())
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
_typeItem.Labels[0].HighlightStripColor = color;
// Check if type has been modified outside the editor (eg. from code)
if (Type != _type)
{

View File

@@ -268,8 +268,8 @@ bool Editor::CheckProjectUpgrade()
// Check if last version was older
else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR))
{
LOG(Warning, "The project was opened with the older editor version last time");
const auto result = MessageBox::Show(TEXT("The project was opened with the older editor version last time. Loading it may modify existing data so older editor version won't open it. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question);
LOG(Warning, "The project was last opened with an older editor version");
const auto result = MessageBox::Show(TEXT("The project was last opened with an older editor version.\nLoading it may modify existing data, which can result in older editor versions being unable to open it.\n\nDo you want to perform a backup before or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question);
if (result == DialogResult::Yes)
{
if (BackupProject())
@@ -291,8 +291,8 @@ bool Editor::CheckProjectUpgrade()
// Check if last version was newer
else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR))
{
LOG(Warning, "The project was opened with the newer editor version last time");
const auto result = MessageBox::Show(TEXT("The project was opened with the newer editor version last time. Loading it may fail and corrupt existing data. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning);
LOG(Warning, "The project was last opened with a newer editor version");
const auto result = MessageBox::Show(TEXT("The project was last opened with a newer editor version.\nLoading it may fail and corrupt existing data.\n\nDo you want to perform a backup before loading or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning);
if (result == DialogResult::Yes)
{
if (BackupProject())

View File

@@ -51,6 +51,7 @@ namespace FlaxEditor
private readonly List<EditorModule> _modules = new List<EditorModule>(16);
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit;
private string _projectToOpen;
private bool _projectIsNew;
private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f;
private Button _saveNowButton;
private Button _cancelSaveButton;
@@ -737,11 +738,12 @@ namespace FlaxEditor
var procSettings = new CreateProcessSettings
{
FileName = Platform.ExecutableFilePath,
Arguments = string.Format("-project \"{0}\"", _projectToOpen),
Arguments = string.Format("-project \"{0}\"" + (_projectIsNew ? " -new" : string.Empty), _projectToOpen),
ShellExecute = true,
WaitForEnd = false,
HiddenWindow = false,
};
_projectIsNew = false;
_projectToOpen = null;
Platform.CreateProcess(ref procSettings);
}
@@ -790,6 +792,24 @@ namespace FlaxEditor
}
}
/// <summary>
/// Creates the given project. Afterwards closes this project with running editor and opens the given project.
/// </summary>
/// <param name="projectFilePath">The project file path.</param>
public void NewProject(string projectFilePath)
{
if (projectFilePath == null)
{
MessageBox.Show("Missing project");
return;
}
// Cache project path and start editor exit (it will open new instance on valid closing)
_projectToOpen = StringUtils.NormalizePath(Path.GetDirectoryName(projectFilePath));
_projectIsNew = true;
Windows.MainWindow.Close(ClosingReason.User);
}
/// <summary>
/// Closes this project with running editor and opens the given project.
/// </summary>

View File

@@ -129,11 +129,39 @@ namespace FlaxEditor.GUI.Input
{
base.Draw();
var style = Style.Current;
var r = new Rectangle(0, 0, Width, Height);
bool isTransparent = _value.A < 1;
Render2D.FillRectangle(r, _value);
Render2D.DrawRectangle(r, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
var style = Style.Current;
var fullRect = new Rectangle(0, 0, Width, Height);
var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height);
if (isTransparent)
{
var alphaRect = new Rectangle(colorRect.Right, 0, Width - colorRect.Right, Height);
// Draw checkerboard pattern to part of the color value box
Render2D.FillRectangle(alphaRect, Color.White);
var smallRectSize = 7.9f;
var numHor = Mathf.CeilToInt(alphaRect.Width / smallRectSize);
var numVer = Mathf.CeilToInt(alphaRect.Height / smallRectSize);
for (int i = 0; i < numHor; i++)
{
for (int j = 0; j < numVer; j++)
{
if ((i + j) % 2 == 0)
{
var rect = new Rectangle(alphaRect.X + smallRectSize * i, alphaRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.PushClip(alphaRect);
Render2D.FillRectangle(rect, Color.Gray);
Render2D.PopClip();
}
}
}
Render2D.FillRectangle(alphaRect, _value);
}
Render2D.FillRectangle(colorRect, _value with { A = 1 });
Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
}
/// <inheritdoc />

View File

@@ -51,6 +51,11 @@ namespace FlaxEditor.GUI
/// </summary>
public float SortScore;
/// <summary>
/// Wether the query highlights should be draw.
/// </summary>
public bool DrawHighlights = true;
/// <summary>
/// Occurs when items gets clicked by the user.
/// </summary>
@@ -165,7 +170,7 @@ namespace FlaxEditor.GUI
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted);
// Draw all highlights
if (_highlights != null)
if (DrawHighlights && _highlights != null)
{
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)

View File

@@ -10,6 +10,7 @@ using System.Text;
using FlaxEditor.GUI.Timeline.Undo;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Timeline.Tracks
@@ -54,7 +55,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var paramTypeName = LoadName(stream);
e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName);
if (e.EventParamsTypes[i] == null)
{
Editor.LogError($"Unknown type {paramTypeName}.");
isInvalid = true;
}
}
if (isInvalid)
@@ -82,7 +86,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++)
{
stream.Read(dataBuffer, 0, e.EventParamsSizes[j]);
key.Parameters[j] = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j]);
key.Parameters[j] = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j], e.EventParamsSizes[j]);
}
events[i] = new KeyframesEditor.Keyframe
@@ -125,8 +129,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++)
{
Marshal.StructureToPtr(key.Parameters[j], ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.EventParamsSizes[j]);
Utilities.Utils.StructureToByteArray(key.Parameters[j], e.EventParamsSizes[j], ptr, dataBuffer);
stream.Write(dataBuffer, 0, e.EventParamsSizes[j]);
}
}
@@ -153,7 +156,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
/// <summary>
/// The event key data.
/// </summary>
public struct EventKey
public struct EventKey : ICloneable
{
/// <summary>
/// The parameters values.
@@ -178,6 +181,26 @@ namespace FlaxEditor.GUI.Timeline.Tracks
sb.Append(')');
return sb.ToString();
}
/// <inheritdoc />
public object Clone()
{
if (Parameters == null)
return new EventKey();
// Deep clone parameter values (especially boxed value types need to be duplicated to avoid referencing the same ones)
var parameters = new object[Parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var p = Parameters[i];
if (p == null || p is FlaxEngine.Object)
parameters[i] = Parameters[i];
else
parameters[i] = JsonSerializer.Deserialize(JsonSerializer.Serialize(p), p.GetType());
}
return new EventKey { Parameters = parameters };
}
}
/// <inheritdoc />
@@ -234,6 +257,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var time = Timeline.CurrentTime;
if (!TryGetValue(out var value))
value = Events.Evaluate(time);
value = ((ICloneable)value).Clone();
// Find event at the current location
for (int i = Events.Keyframes.Count - 1; i >= 0; i--)

View File

@@ -77,7 +77,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
{
var time = stream.ReadSingle();
stream.Read(dataBuffer, 0, e.ValueSize);
var value = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), propertyType);
var value = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), propertyType, e.ValueSize);
keyframes[i] = new KeyframesEditor.Keyframe
{
@@ -142,8 +142,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int i = 0; i < keyframes.Count; i++)
{
var keyframe = keyframes[i];
Marshal.StructureToPtr(keyframe.Value, ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.ValueSize);
Utilities.Utils.StructureToByteArray(keyframe.Value, e.ValueSize, ptr, dataBuffer);
stream.Write(keyframe.Time);
stream.Write(dataBuffer);
}

View File

@@ -1,9 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Options;
using FlaxEditor.SceneGraph;
using FlaxEngine;
using System;
namespace FlaxEditor.Gizmo
{
@@ -21,12 +19,16 @@ namespace FlaxEditor.Gizmo
private MaterialInstance _materialAxisY;
private MaterialInstance _materialAxisZ;
private MaterialInstance _materialAxisFocus;
private MaterialInstance _materialAxisLocked;
private MaterialBase _materialSphere;
// Material Parameter Names
const String _brightnessParamName = "Brightness";
const String _opacityParamName = "Opacity";
private const string _brightnessParamName = "Brightness";
private const string _opacityParamName = "Opacity";
/// <summary>
/// Used for example when the selection can't be moved because one actor is static.
/// </summary>
private bool _isDisabled;
private void InitDrawing()
{
@@ -42,7 +44,6 @@ namespace FlaxEditor.Gizmo
_materialAxisY = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisY");
_materialAxisZ = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisZ");
_materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisFocus");
_materialAxisLocked = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisLocked");
_materialSphere = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialSphere");
// Ensure that every asset was loaded
@@ -67,17 +68,42 @@ namespace FlaxEditor.Gizmo
private void OnEditorOptionsChanged(EditorOptions options)
{
float brightness = options.Visual.TransformGizmoBrightness;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
_materialAxisLocked.SetParameterValue(_brightnessParamName, brightness);
UpdateGizmoBrightness(options);
float opacity = options.Visual.TransformGizmoOpacity;
_materialAxisX.SetParameterValue(_opacityParamName, opacity);
_materialAxisY.SetParameterValue(_opacityParamName, opacity);
_materialAxisZ.SetParameterValue(_opacityParamName, opacity);
_materialAxisLocked.SetParameterValue(_opacityParamName, opacity);
}
private void UpdateGizmoBrightness(EditorOptions options)
{
_isDisabled = ShouldGizmoBeLocked();
float brightness = _isDisabled ? options.Visual.TransformGizmoBrightnessDisabled : options.Visual.TransformGizmoBrightness;
if (Mathf.NearEqual(brightness, (float)_materialAxisX.GetParameterValue(_brightnessParamName)))
return;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
}
private bool ShouldGizmoBeLocked()
{
bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode && Owner is Viewport.EditorGizmoViewport)
{
// Block editing static scene objects in main view during play mode
foreach (var obj in Editor.Instance.SceneEditing.Selection)
{
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
return gizmoLocked;
}
/// <inheritdoc />
@@ -88,20 +114,8 @@ namespace FlaxEditor.Gizmo
if (!_modelCube || !_modelCube.IsLoaded)
return;
// Find out if any of the selected objects can not be moved
bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode)
{
for (int i = 0; i < SelectionCount; i++)
{
var obj = GetSelectedObject(i);
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
// Update the gizmo brightness every frame to ensure it updates correctly
UpdateGizmoBrightness(Editor.Instance.Options.Options);
// As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order
// https://github.com/FlaxEngine/FlaxEngine/issues/680
@@ -136,37 +150,37 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialTransform = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
MaterialInstance yAxisMaterialTransform = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis
Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
MaterialInstance zAxisMaterialTransform = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
MaterialInstance xyPlaneMaterialTransform = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY);
MaterialInstance zxPlaneMaterialTransform = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ);
MaterialInstance yzPlaneMaterialTransform = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center sphere
@@ -186,17 +200,17 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis
Matrix.RotationX(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box
@@ -216,37 +230,37 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref mx1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis
Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
MaterialInstance xyPlaneMaterialScale = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ);
MaterialInstance zxPlaneMaterialScale = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY);
MaterialInstance yzPlaneMaterialScale = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box

View File

@@ -155,6 +155,16 @@ namespace FlaxEditor
private List<Widget> _widgets;
private Widget _activeWidget;
/// <summary>
/// Sets the view size.
/// </summary>
/// <param name="size">The new size.</param>
public void SetViewSize(Float2 size)
{
_view.Size = size;
_view.PerformLayout();
}
/// <summary>
/// True if enable displaying UI editing background and grid elements.
/// </summary>

View File

@@ -673,6 +673,7 @@ namespace FlaxEditor.Modules
pasteAction.Do(out _, out var nodeParents);
// Select spawned objects (parents only)
newSelection.Clear();
newSelection.AddRange(nodeParents);
var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo);
selectAction.Do();

View File

@@ -54,6 +54,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing
case CodeEditorTypes.VS2022:
Name = "Visual Studio 2022";
break;
case CodeEditorTypes.VS2026:
Name = "Visual Studio 2026";
break;
case CodeEditorTypes.VSCode:
Name = "Visual Studio Code";
break;
@@ -110,6 +113,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
case CodeEditorTypes.VS2017:
case CodeEditorTypes.VS2019:
case CodeEditorTypes.VS2022:
case CodeEditorTypes.VS2026:
// TODO: finish dynamic files adding to the project
//Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync();
break;

View File

@@ -70,6 +70,53 @@ namespace FlaxEditor.Modules
private bool _progressFailed;
ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>();
/// <summary>
/// Defines a viewport scaling option.
/// </summary>
public class ViewportScaleOption
{
/// <summary>
/// Defines the viewport scale type.
/// </summary>
public enum ViewportScaleType
{
/// <summary>
/// Resolution.
/// </summary>
Resolution = 0,
/// <summary>
/// Aspect Ratio.
/// </summary>
Aspect = 1,
}
/// <summary>
/// The name.
/// </summary>
public string Label;
/// <summary>
/// The Type of scaling to do.
/// </summary>
public ViewportScaleType ScaleType;
/// <summary>
/// The width and height to scale by.
/// </summary>
public Int2 Size;
}
/// <summary>
/// The default viewport scaling options.
/// </summary>
public List<ViewportScaleOption> DefaultViewportScaleOptions = new List<ViewportScaleOption>();
/// <summary>
/// The user defined viewport scaling options.
/// </summary>
public List<ViewportScaleOption> CustomViewportScaleOptions = new List<ViewportScaleOption>();
private ContextMenuButton _menuFileSaveScenes;
private ContextMenuButton _menuFileReloadScenes;
@@ -409,6 +456,8 @@ namespace FlaxEditor.Modules
// Update window background
mainWindow.BackgroundColor = Style.Current.Background;
InitViewportScaleOptions();
InitSharedMenus();
InitMainMenu(mainWindow);
@@ -422,6 +471,57 @@ namespace FlaxEditor.Modules
mainWindow.PerformLayout(true);
}
private void InitViewportScaleOptions()
{
if (DefaultViewportScaleOptions.Count == 0)
{
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "Free Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(1, 1),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:9 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 9),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:10 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 10),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "1920x1080 Resolution (Full HD)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(1920, 1080),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "2560x1440 Resolution (2K)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(2560, 1440),
});
}
if (Editor.Instance.ProjectCache.TryGetCustomData("CustomViewportScalingOptions", out string data))
{
CustomViewportScaleOptions = JsonSerializer.Deserialize<List<ViewportScaleOption>>(data);
}
}
/// <summary>
/// Saves the custom viewport scaling options.
/// </summary>
public void SaveCustomViewportScalingOptions()
{
var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions);
Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions);
}
/// <inheritdoc />
public override void OnUpdate()
{
@@ -546,6 +646,7 @@ namespace FlaxEditor.Modules
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
_menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile);
cm.AddSeparator();
cm.AddButton("New project", NewProject);
cm.AddButton("Open project...", OpenProject);
cm.AddButton("Reload project", ReloadProject);
cm.AddButton("Open project folder", () => FileSystem.ShowFileExplorer(Editor.Instance.GameProject.ProjectFolderPath));
@@ -576,7 +677,7 @@ namespace FlaxEditor.Modules
if (item != null)
Editor.ContentEditing.Open(item);
});
cm.AddButton("Editor Options", () => Editor.Windows.EditorOptionsWin.Show());
cm.AddButton("Editor Options", inputOptions.EditorOptionsWindow, () => Editor.Windows.EditorOptionsWin.Show());
// Scene
MenuScene = MainMenu.AddButton("Scene");
@@ -851,6 +952,17 @@ namespace FlaxEditor.Modules
MasterPanel.Offsets = new Margin(0, 0, ToolStrip.Bottom, StatusBar.Height);
}
private void NewProject()
{
// Ask user to create project file
if (FileSystem.ShowSaveFileDialog(Editor.Windows.MainWindow, null, "Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0", false, "Create project file", out var files))
return;
if (files != null && files.Length > 0)
{
Editor.NewProject(files[0]);
}
}
private void OpenProject()
{
// Ask user to select project file
@@ -1108,5 +1220,267 @@ namespace FlaxEditor.Modules
MenuTools = null;
MenuHelp = null;
}
internal void CreateViewportSizingContextMenu(ContextMenu vsMenu, int defaultScaleActiveIndex, int customScaleActiveIndex, bool prefabViewport, Action<ViewportScaleOption> changeView, Action<int, int> changeActiveIndices)
{
// Add default viewport sizing options
var defaultOptions = DefaultViewportScaleOptions;
for (int i = 0; i < defaultOptions.Count; i++)
{
var viewportScale = defaultOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var button = vsMenu.AddButton(viewportScale.Label);
button.CloseMenuOnClick = false;
button.Tag = viewportScale;
// No default index is active
if (defaultScaleActiveIndex == -1)
{
button.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (defaultScaleActiveIndex == i)
{
button.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
button.Clicked += () =>
{
if (button.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (cmb == button)
{
button.Icon = Style.Current.CheckBoxTick;
var index = defaultOptions.FindIndex(x => x == v);
changeActiveIndices(index, -1); // Reset custom index because default was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
}
if (defaultOptions.Count != 0)
vsMenu.AddSeparator();
// Add custom viewport options
var customOptions = CustomViewportScaleOptions;
for (int i = 0; i < customOptions.Count; i++)
{
var viewportScale = customOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var childCM = vsMenu.AddChildMenu(viewportScale.Label);
childCM.CloseMenuOnClick = false;
childCM.Tag = viewportScale;
// No custom index is active
if (customScaleActiveIndex == -1)
{
childCM.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (customScaleActiveIndex == i)
{
childCM.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
var applyButton = childCM.ContextMenu.AddButton("Apply");
applyButton.Tag = childCM.Tag = viewportScale;
applyButton.CloseMenuOnClick = false;
applyButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (child == childCM)
{
childCM.Icon = Style.Current.CheckBoxTick;
var index = customOptions.FindIndex(x => x == v);
changeActiveIndices(-1, index); // Reset default index because custom was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
var deleteButton = childCM.ContextMenu.AddButton("Delete");
deleteButton.CloseMenuOnClick = false;
deleteButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
var v = (ViewportScaleOption)childCM.Tag;
if (childCM.Icon != SpriteHandle.Invalid)
{
changeActiveIndices(-1, 0);
changeView(defaultOptions[0]);
}
customOptions.Remove(v);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
}
if (customOptions.Count != 0)
vsMenu.AddSeparator();
// Add button
var add = vsMenu.AddButton("Add...");
add.CloseMenuOnClick = false;
add.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(add, new Float2(add.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var typeLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Type",
HorizontalAlignment = TextAlignment.Near,
};
typeLabel.LocalX += 10;
typeLabel.LocalY += 35;
var typeDropdown = new Dropdown
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Items = { "Aspect", "Resolution" },
SelectedItem = "Aspect",
Visible = !prefabViewport,
Width = nameTextBox.Width
};
typeDropdown.LocalY += 35;
typeDropdown.LocalX += 100;
var whLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Width & Height",
HorizontalAlignment = TextAlignment.Near,
};
whLabel.LocalX += 10;
whLabel.LocalY += 60;
var wValue = new IntValueBox(16)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
wValue.LocalY += 60;
wValue.LocalX += 100;
var hValue = new IntValueBox(9)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
hValue.LocalY += 60;
hValue.LocalX += 165;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Submit",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleOption.ViewportScaleType type);
if (prefabViewport)
type = ViewportScaleOption.ViewportScaleType.Resolution;
var combineString = type == ViewportScaleOption.ViewportScaleType.Aspect ? ":" : "x";
var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem;
var newViewportOption = new ViewportScaleOption
{
ScaleType = type,
Label = name,
Size = new Int2(wValue.Value, hValue.Value),
};
customOptions.Add(newViewportOption);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
typeDropdown.SelectedItem = "Aspect";
hValue.Value = 9;
wValue.Value = 16;
popup.Hide();
};
};
}
}
}

View File

@@ -650,6 +650,10 @@ namespace FlaxEditor.Options
[EditorDisplay("Windows"), EditorOrder(4020)]
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Control+Comma")]
[EditorDisplay("Windows"), EditorOrder(4030)]
public InputBinding EditorOptionsWindow = new InputBinding(KeyboardKeys.Comma, KeyboardKeys.Control);
#endregion
#region Node Editors

View File

@@ -150,5 +150,26 @@ namespace FlaxEditor.Options
[DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")]
[EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")]
public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f);
/// <summary>
/// Gets or sets the minimum size used for viewport icons.
/// </summary>
[DefaultValue(7.0f), Limit(1.0f, 1000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(400)]
public float IconsMinimumSize { get; set; } = 7.0f;
/// <summary>
/// Gets or sets the maximum size used for viewport icons.
/// </summary>
[DefaultValue(30.0f), Limit(1.0f, 1000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(410)]
public float IconsMaximumSize { get; set; } = 30.0f;
/// <summary>
/// Gets or sets the distance towards the camera at which the max icon scale will be applied. Set to 0 to disable scaling the icons based on the distance to the camera.
/// </summary>
[DefaultValue(1000.0f), Limit(0.0f, 20000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(410)]
public float MaxSizeDistance { get; set; } = 1000.0f;
}
}

View File

@@ -81,6 +81,13 @@ namespace FlaxEditor.Options
[EditorDisplay("Transform Gizmo", "Gizmo Opacity"), EditorOrder(211)]
public float TransformGizmoOpacity { get; set; } = 1f;
/// <summary>
/// Gets or set a value indicating how bright the transform gizmo is when it is disabled, for example when one of the selected actors is static in play mode. Use a value of 0 to make the gizmo fully gray. Value over 1 will result in the gizmo emitting light.
/// </summary>
[DefaultValue(0.25f), Range(0f, 5f)]
[EditorDisplay("Transform Gizmo", "Disabled Gizmo Brightness"), EditorOrder(212)]
public float TransformGizmoBrightnessDisabled { get; set; } = 0.25f;
/// <summary>
/// Gets or sets a value indicating whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance.
/// </summary>

View File

@@ -62,6 +62,11 @@ API_ENUM(Namespace="FlaxEditor", Attributes="HideInEditor") enum class CodeEdito
/// </summary>
VS2022,
/// <summary>
/// Visual Studio 2026
/// </summary>
VS2026,
/// <summary>
/// Visual Studio Code
/// </summary>

View File

@@ -43,6 +43,9 @@ VisualStudioEditor::VisualStudioEditor(VisualStudioVersion version, const String
case VisualStudioVersion::VS2022:
_type = CodeEditorTypes::VS2022;
break;
case VisualStudioVersion::VS2026:
_type = CodeEditorTypes::VS2026;
break;
default: CRASH;
break;
}
@@ -70,6 +73,9 @@ void VisualStudioEditor::FindEditors(Array<CodeEditor*>* output)
VisualStudioVersion version;
switch (info.VersionMajor)
{
case 18:
version = VisualStudioVersion::VS2026;
break;
case 17:
version = VisualStudioVersion::VS2022;
break;

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Microsoft Visual Studio version types
/// </summary>
DECLARE_ENUM_8(VisualStudioVersion, VS2008, VS2010, VS2012, VS2013, VS2015, VS2017, VS2019, VS2022);
DECLARE_ENUM_9(VisualStudioVersion, VS2008, VS2010, VS2012, VS2013, VS2015, VS2017, VS2019, VS2022, VS2026);
/// <summary>
/// Implementation of code editor utility that is using Microsoft Visual Studio.

View File

@@ -229,20 +229,20 @@ namespace FlaxEditor.Surface
}
/// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes)
{
// Check if show additional nodes in the current surface context
if (activeCM != _cmStateMachineMenu)
{
_nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBox);
base.OnShowPrimaryMenu(activeCM, location, startBoxes);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
}
else
{
base.OnShowPrimaryMenu(activeCM, location, startBox);
base.OnShowPrimaryMenu(activeCM, location, startBoxes);
}
}

View File

@@ -1390,7 +1390,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[]
{
NodeElementArchetype.Factory.Output(0, "Time", typeof(float), 0),
NodeElementArchetype.Factory.Output(1, "Unscaled Time", typeof(float), 1),
NodeElementArchetype.Factory.Output(1, "Scaled Time", typeof(float), 1),
}
},
new NodeArchetype

View File

@@ -101,12 +101,12 @@ namespace FlaxEditor.Surface
}
/// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes)
{
activeCM.ShowExpanded = true;
_nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBox);
base.OnShowPrimaryMenu(activeCM, location, startBoxes);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
}

View File

@@ -24,8 +24,8 @@ namespace FlaxEditor.Surface.ContextMenu
/// Visject context menu item clicked delegate.
/// </summary>
/// <param name="clickedItem">The item that was clicked</param>
/// <param name="selectedBox">The currently user-selected box. Can be null.</param>
public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, Elements.Box selectedBox);
/// <param name="selectedBoxes">The currently user-selected boxes. Can be empty/ null.</param>
public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, List<Elements.Box> selectedBoxes);
/// <summary>
/// Visject Surface node archetype spawn ability checking delegate.
@@ -53,7 +53,7 @@ namespace FlaxEditor.Surface.ContextMenu
private Panel _panel1;
private VerticalPanel _groupsPanel;
private readonly ParameterGetterDelegate _parametersGetter;
private Elements.Box _selectedBox;
private List<Elements.Box> _selectedBoxes = new List<Elements.Box>();
private NodeArchetype _parameterGetNodeArchetype;
private NodeArchetype _parameterSetNodeArchetype;
@@ -411,7 +411,8 @@ namespace FlaxEditor.Surface.ContextMenu
if (!IsLayoutLocked)
{
group.UnlockChildrenRecursive();
if (_contextSensitiveSearchEnabled && _selectedBox != null)
// TODO: Improve filtering to be based on boxes with the most common things instead of first box
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null)
UpdateFilters();
else
SortGroups();
@@ -423,9 +424,10 @@ namespace FlaxEditor.Surface.ContextMenu
OnSearchFilterChanged();
}
}
else if (_contextSensitiveSearchEnabled)
else if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0)
{
group.EvaluateVisibilityWithBox(_selectedBox);
// TODO: Filtering could be improved here as well
group.EvaluateVisibilityWithBox(_selectedBoxes[0]);
}
Profiler.EndEvent();
@@ -460,8 +462,8 @@ namespace FlaxEditor.Surface.ContextMenu
Parent = group
};
}
if (_contextSensitiveSearchEnabled)
group.EvaluateVisibilityWithBox(_selectedBox);
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0)
group.EvaluateVisibilityWithBox(_selectedBoxes[0]);
group.SortChildren();
if (ShowExpanded)
group.Open(false);
@@ -474,7 +476,7 @@ namespace FlaxEditor.Surface.ContextMenu
if (!isLayoutLocked)
{
if (_contextSensitiveSearchEnabled && _selectedBox != null)
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count != 0 && _selectedBoxes[0] != null)
UpdateFilters();
else
SortGroups();
@@ -583,7 +585,7 @@ namespace FlaxEditor.Surface.ContextMenu
private void UpdateFilters()
{
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBox == null)
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes[0] == null)
{
ResetView();
Profiler.EndEvent();
@@ -592,7 +594,7 @@ namespace FlaxEditor.Surface.ContextMenu
// Update groups
LockChildrenRecursive();
var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled ? _selectedBox : null;
var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 ? _selectedBoxes[0] : null;
for (int i = 0; i < _groups.Count; i++)
{
_groups[i].UpdateFilter(_searchBox.Text, contextSensitiveSelectedBox);
@@ -640,7 +642,7 @@ namespace FlaxEditor.Surface.ContextMenu
public void OnClickItem(VisjectCMItem item)
{
Hide();
ItemClicked?.Invoke(item, _selectedBox);
ItemClicked?.Invoke(item, _selectedBoxes);
}
/// <summary>
@@ -666,12 +668,12 @@ namespace FlaxEditor.Surface.ContextMenu
for (int i = 0; i < _groups.Count; i++)
{
_groups[i].ResetView();
if (_contextSensitiveSearchEnabled)
_groups[i].EvaluateVisibilityWithBox(_selectedBox);
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0)
_groups[i].EvaluateVisibilityWithBox(_selectedBoxes[0]);
}
UnlockChildrenRecursive();
if (_contextSensitiveSearchEnabled && _selectedBox != null)
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null)
UpdateFilters();
else
SortGroups();
@@ -772,10 +774,10 @@ namespace FlaxEditor.Surface.ContextMenu
/// </summary>
/// <param name="parent">Parent control to attach to it.</param>
/// <param name="location">Popup menu origin location in parent control coordinates.</param>
/// <param name="startBox">The currently selected box that the new node will get connected to. Can be null</param>
public void Show(Control parent, Float2 location, Elements.Box startBox)
/// <param name="startBoxes">The currently selected boxes that the new node will get connected to. Can be empty/ null</param>
public void Show(Control parent, Float2 location, List<Elements.Box> startBoxes)
{
_selectedBox = startBox;
_selectedBoxes = startBoxes;
base.Show(parent, location);
}

View File

@@ -544,35 +544,39 @@ namespace FlaxEditor.Surface.Elements
public override void OnMouseLeave()
{
if (_originalTooltipText != null)
{
TooltipText = _originalTooltipText;
}
if (_isMouseDown)
{
_isMouseDown = false;
if (Surface.CanEdit)
{
if (!IsOutput && HasSingleConnection)
if (IsOutput && Input.GetKey(KeyboardKeys.Control))
{
var connectedBox = Connections[0];
List<Box> connectedBoxes = new List<Box>(Connections);
for (int i = 0; i < connectedBoxes.Count; i++)
{
BreakConnection(connectedBoxes[i]);
Surface.ConnectingStart(connectedBoxes[i], true);
}
}
else if (!IsOutput && HasSingleConnection)
{
var otherBox = Connections[0];
if (Surface.Undo != null && Surface.Undo.Enabled)
{
var action = new ConnectBoxesAction((InputBox)this, (OutputBox)connectedBox, false);
BreakConnection(connectedBox);
var action = new ConnectBoxesAction((InputBox)this, (OutputBox)otherBox, false);
BreakConnection(otherBox);
action.End();
Surface.AddBatchedUndoAction(action);
Surface.MarkAsEdited();
}
else
{
BreakConnection(connectedBox);
}
Surface.ConnectingStart(connectedBox);
BreakConnection(otherBox);
Surface.ConnectingStart(otherBox);
}
else
{
Surface.ConnectingStart(this);
}
}
}
base.OnMouseLeave();

View File

@@ -151,6 +151,8 @@ namespace FlaxEditor.Surface
/// </summary>
protected virtual Color FooterColor => GroupArchetype.Color;
private Float2 mouseDownMousePosition;
/// <summary>
/// Calculates the size of the node including header, footer, and margins.
/// </summary>
@@ -917,7 +919,7 @@ namespace FlaxEditor.Surface
/// <inheritdoc />
public override bool OnTestTooltipOverControl(ref Float2 location)
{
return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting;
return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsSelecting;
}
/// <inheritdoc />
@@ -1075,7 +1077,7 @@ namespace FlaxEditor.Surface
// Header
var headerColor = style.BackgroundHighlighted;
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting)
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting)
headerColor *= 1.07f;
Render2D.FillRectangle(_headerRect, headerColor);
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
@@ -1083,7 +1085,7 @@ namespace FlaxEditor.Surface
// Close button
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
{
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting;
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting;
Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
}
@@ -1121,7 +1123,7 @@ namespace FlaxEditor.Surface
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
return true;
if (button == MouseButton.Right)
return true;
mouseDownMousePosition = Input.Mouse.Position;
return false;
}
@@ -1133,7 +1135,7 @@ namespace FlaxEditor.Surface
return true;
// Close/ delete
bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection;
bool canDelete = !Surface.IsConnecting && !Surface.WasSelecting && !Surface.WasMovingSelection;
if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
{
Surface.Delete(this);
@@ -1143,6 +1145,10 @@ namespace FlaxEditor.Surface
// Secondary Context Menu
if (button == MouseButton.Right)
{
float distance = Float2.Distance(mouseDownMousePosition, Input.Mouse.Position);
if (distance > 2.5f)
return true;
if (!IsSelected)
Surface.Select(this);
var tmp = PointToParent(ref location);

View File

@@ -1,6 +1,8 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEngine;
namespace FlaxEditor.Surface
@@ -233,11 +235,15 @@ namespace FlaxEditor.Surface
/// Begins connecting surface objects action.
/// </summary>
/// <param name="instigator">The connection instigator (eg. start box).</param>
public void ConnectingStart(IConnectionInstigator instigator)
/// <param name="additive">If the instigator should be added to the list of instigators.</param>
public void ConnectingStart(IConnectionInstigator instigator, bool additive = false)
{
if (instigator != null && instigator != _connectionInstigator)
if (instigator != null && instigator != _connectionInstigators)
{
_connectionInstigator = instigator;
if (!additive)
_connectionInstigators.Clear();
_connectionInstigators.Add(instigator);
StartMouseCapture();
}
}
@@ -257,22 +263,30 @@ namespace FlaxEditor.Surface
/// <param name="end">The end object (eg. end box).</param>
public void ConnectingEnd(IConnectionInstigator end)
{
// Ensure that there was a proper start box
if (_connectionInstigator == null)
// Ensure that there is at least one connection instigator
if (_connectionInstigators.Count == 0)
return;
var start = _connectionInstigator;
_connectionInstigator = null;
// Check if boxes are different and end box is specified
if (start == end || end == null)
return;
// Connect them
if (start.CanConnectWith(end))
List<IConnectionInstigator> instigators = new List<IConnectionInstigator>(_connectionInstigators);
for (int i = 0; i < instigators.Count; i++)
{
start.Connect(end);
var start = instigators[i];
// Check if boxes are different and end box is specified
if (start == end || end == null)
return;
// Properly handle connecting to a socket that already has a connection
if (end is Box e && !e.IsOutput && start is Box s && e.AreConnected(s))
e.BreakConnection(s);
// Connect them
if (start.CanConnectWith(end))
start.Connect(end);
}
// Reset instigator list
_connectionInstigators.Clear();
}
}
}

View File

@@ -261,10 +261,10 @@ namespace FlaxEditor.Surface
/// </summary>
/// <param name="activeCM">The active context menu to show.</param>
/// <param name="location">The display location on the surface control.</param>
/// <param name="startBox">The start box.</param>
protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
/// <param name="startBoxes">The start boxes.</param>
protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes)
{
activeCM.Show(this, location, startBox);
activeCM.Show(this, location, startBoxes);
}
/// <summary>
@@ -298,8 +298,10 @@ namespace FlaxEditor.Surface
_cmStartPos = location;
// Offset added in case the user doesn't like the box and wants to quickly get rid of it by clicking
OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, _connectionInstigator as Box);
List<Box> startBoxes = new List<Box>(_connectionInstigators.Where(c => c is Box).Cast<Box>());
// Position offset added so the user can quickly close the menu by clicking
OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, startBoxes);
if (!string.IsNullOrEmpty(input))
{
@@ -513,17 +515,15 @@ namespace FlaxEditor.Surface
private void OnPrimaryMenuVisibleChanged(Control primaryMenu)
{
if (!primaryMenu.Visible)
{
_connectionInstigator = null;
}
_connectionInstigators.Clear();
}
/// <summary>
/// Handles Visject CM item click event by spawning the selected item.
/// </summary>
/// <param name="visjectCmItem">The item.</param>
/// <param name="selectedBox">The selected box.</param>
protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, Box selectedBox)
/// <param name="selectedBoxes">The selected boxes.</param>
protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, List<Box> selectedBoxes)
{
if (!CanEdit)
return;
@@ -550,34 +550,36 @@ namespace FlaxEditor.Surface
// Auto select new node
Select(node);
if (selectedBox != null)
for (int i = 0; i < selectedBoxes.Count; i++)
{
Box endBox = null;
foreach (var box in node.GetBoxes().Where(box => box.IsOutput != selectedBox.IsOutput))
Box currentBox = selectedBoxes[i];
if (currentBox != null)
{
if (selectedBox.IsOutput)
Box endBox = null;
foreach (var box in node.GetBoxes().Where(box => box.IsOutput != currentBox.IsOutput))
{
if (box.CanUseType(selectedBox.CurrentType))
if (currentBox.IsOutput)
{
endBox = box;
break;
if (box.CanUseType(currentBox.CurrentType))
{
endBox = box;
break;
}
}
}
else
{
if (selectedBox.CanUseType(box.CurrentType))
else
{
endBox = box;
break;
if (currentBox.CanUseType(box.CurrentType))
{
endBox = box;
break;
}
}
}
if (endBox == null && selectedBox.CanUseType(box.CurrentType))
{
endBox = box;
if (endBox == null && currentBox.CanUseType(box.CurrentType))
endBox = box;
}
TryConnect(currentBox, endBox);
}
TryConnect(selectedBox, endBox);
}
}
@@ -593,13 +595,8 @@ namespace FlaxEditor.Surface
}
// If the user is patiently waiting for his box to get connected to the newly created one fulfill his wish!
_connectionInstigator = startBox;
if (!IsConnecting)
{
ConnectingStart(startBox);
}
ConnectingEnd(endBox);
// Smart-Select next box

View File

@@ -1,5 +1,6 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Surface.Elements;
using FlaxEngine;
@@ -126,40 +127,45 @@ namespace FlaxEditor.Surface
/// <remarks>Called only when user is connecting nodes.</remarks>
protected virtual void DrawConnectingLine()
{
// Get start position
var startPos = _connectionInstigator.ConnectionOrigin;
// Check if mouse is over any of box
var cmVisible = _activeVisjectCM != null && _activeVisjectCM.Visible;
var endPos = cmVisible ? _rootControl.PointFromParent(ref _cmStartPos) : _rootControl.PointFromParent(ref _mousePos);
Color lineColor = Style.Colors.Connecting;
if (_lastInstigatorUnderMouse != null && !cmVisible)
{
// Check if can connect objects
bool canConnect = _connectionInstigator.CanConnectWith(_lastInstigatorUnderMouse);
lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid;
endPos = _lastInstigatorUnderMouse.ConnectionOrigin;
}
Float2 actualStartPos = startPos;
Float2 actualEndPos = endPos;
if (_connectionInstigator is Archetypes.Tools.RerouteNode)
List<IConnectionInstigator> instigators = new List<IConnectionInstigator>(_connectionInstigators);
for (int i = 0; i < instigators.Count; i++)
{
if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true })
IConnectionInstigator currentInstigator = instigators[i];
Float2 currentStartPosition = currentInstigator.ConnectionOrigin;
// Check if mouse is over any box
if (_lastInstigatorUnderMouse != null && !cmVisible)
{
// Check if can connect objects
bool canConnect = currentInstigator.CanConnectWith(_lastInstigatorUnderMouse);
lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid;
endPos = _lastInstigatorUnderMouse.ConnectionOrigin;
}
Float2 actualStartPos = currentStartPosition;
Float2 actualEndPos = endPos;
if (currentInstigator is Archetypes.Tools.RerouteNode)
{
if (endPos.X < currentStartPosition.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true })
{
actualStartPos = endPos;
actualEndPos = currentStartPosition;
}
}
else if (currentInstigator is Box { IsOutput: false })
{
actualStartPos = endPos;
actualEndPos = startPos;
actualEndPos = currentStartPosition;
}
}
else if (_connectionInstigator is Box { IsOutput: false })
{
actualStartPos = endPos;
actualEndPos = startPos;
}
// Draw connection
_connectionInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor);
// Draw connection
currentInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor);
}
}
/// <summary>
@@ -226,10 +232,10 @@ namespace FlaxEditor.Surface
_rootControl.DrawComments();
// Reset input flags here because this is the closest to Update we have
WasBoxSelecting = IsBoxSelecting;
WasSelecting = IsSelecting;
WasMovingSelection = IsMovingSelection;
if (IsBoxSelecting)
if (IsSelecting)
{
DrawSelection();
}

View File

@@ -176,10 +176,10 @@ namespace FlaxEditor.Surface
if (connectedNodes.Count == 0)
return;
for (int i = 0; i < connectedNodes.Count - 1; i++)
for (int i = 0; i < connectedNodes.Count; i++)
{
SurfaceNode nodeA = connectedNodes[i];
List<Box> connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.IsOutput && b.HasAnyConnection).ToList();
List<Box> connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.HasAnyConnection).ToList();
for (int j = 0; j < connectedOutputBoxes.Count; j++)
{

View File

@@ -292,7 +292,7 @@ namespace FlaxEditor.Surface
if (_leftMouseDown)
{
// Connecting
if (_connectionInstigator != null)
if (_connectionInstigators.Count > 0)
{
}
// Moving
@@ -462,7 +462,7 @@ namespace FlaxEditor.Surface
public override bool OnMouseDown(Float2 location, MouseButton button)
{
// Check if user is connecting boxes
if (_connectionInstigator != null)
if (_connectionInstigators.Count > 0)
return true;
// Base
@@ -608,7 +608,7 @@ namespace FlaxEditor.Surface
_movingNodesDelta = Float2.Zero;
}
// Connecting
else if (_connectionInstigator != null)
else if (_connectionInstigators.Count > 0)
{
}
// Selecting
@@ -680,7 +680,7 @@ namespace FlaxEditor.Surface
ShowPrimaryMenu(_cmStartPos);
}
// Letting go of a connection or right clicking while creating a connection
else if (!_isMovingSelection && _connectionInstigator != null && !IsPrimaryMenuOpened)
else if (!_isMovingSelection && _connectionInstigators.Count > 0 && !IsPrimaryMenuOpened)
{
_cmStartPos = location;
Cursor = CursorType.Default;

View File

@@ -33,7 +33,7 @@ namespace FlaxEditor.Surface
Enabled = false;
// Clean data
_connectionInstigator = null;
_connectionInstigators.Clear();
_lastInstigatorUnderMouse = null;
var failed = RootContext.Load();

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.Surface
/// <summary>
/// The connection start.
/// </summary>
protected IConnectionInstigator _connectionInstigator;
protected List<IConnectionInstigator> _connectionInstigators = new List<IConnectionInstigator>();
/// <summary>
/// The last connection instigator under mouse.
@@ -232,19 +232,19 @@ namespace FlaxEditor.Surface
}
/// <summary>
/// Gets a value indicating whether user is box selecting nodes.
/// Gets a value indicating whether user is selecting nodes.
/// </summary>
public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigators.Count == 0;
/// <summary>
/// Gets a value indicating whether user was previously box selecting nodes.
/// Gets a value indicating whether user was previously selecting nodes.
/// </summary>
public bool WasBoxSelecting { get; private set; }
public bool WasSelecting { get; private set; }
/// <summary>
/// Gets a value indicating whether user is moving selected nodes.
/// </summary>
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null;
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigators.Count == 0;
/// <summary>
/// Gets a value indicating whether user was previously moving selected nodes.
@@ -254,7 +254,7 @@ namespace FlaxEditor.Surface
/// <summary>
/// Gets a value indicating whether user is connecting nodes.
/// </summary>
public bool IsConnecting => _connectionInstigator != null;
public bool IsConnecting => _connectionInstigators.Count > 0;
/// <summary>
/// Gets a value indicating whether the left mouse button is down.

View File

@@ -212,7 +212,7 @@ namespace FlaxEditor.Surface
}
/// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes)
{
// Update nodes for method overrides
Profiler.BeginEvent("Overrides");
@@ -268,7 +268,7 @@ namespace FlaxEditor.Surface
// Update nodes for invoke methods (async)
_nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBox);
base.OnShowPrimaryMenu(activeCM, location, startBoxes);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
}

View File

@@ -149,13 +149,13 @@ bool GetTextureDataForSampling(Texture* texture, TextureDataResult& data, bool h
bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches, Texture* heightmap, float heightmapScale, Texture* splatmap1, Texture* splatmap2)
{
PROFILE_CPU_NAMED("Terrain.GenerateTerrain");
CHECK_RETURN(terrain && terrain->GetChunkSize() != 0, true);
if (numberOfPatches.X < 1 || numberOfPatches.Y < 1)
{
LOG(Warning, "Cannot setup terain with no patches.");
LOG(Warning, "Cannot setup terrain with no patches.");
return false;
}
PROFILE_CPU_NAMED("Terrain.GenerateTerrain");
// Wait for assets to be loaded
if (heightmap && heightmap->WaitForLoaded())
@@ -178,7 +178,9 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
terrain->AddPatches(numberOfPatches);
// Prepare data
const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
const int32 heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
const float heightmapSizeInv = 1.0f / (float)(heightmapSize - 1);
const Float2 uvPerPatch = Float2::One / Float2(numberOfPatches);
Array<float> heightmapData;
heightmapData.Resize(heightmapSize * heightmapSize);
@@ -192,19 +194,17 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
const auto sampler = PixelFormatSampler::Get(dataHeightmap.Format);
// Initialize with sub-range of the input heightmap
const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches);
const float heightmapSizeInv = 1.0f / (heightmapSize - 1);
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{
auto patch = terrain->GetPatch(patchIndex);
const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
// Sample heightmap pixels with interpolation to get actual heightmap vertices locations
for (int32 z = 0; z < heightmapSize; z++)
{
for (int32 x = 0; x < heightmapSize; x++)
{
const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Color color = sampler->SampleLinear(dataHeightmap.Mip0DataPtr->Get(), uv, dataHeightmap.Mip0Size, dataHeightmap.RowPitch);
heightmapData[z * heightmapSize + x] = color.R * heightmapScale;
}
@@ -230,37 +230,30 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
Texture* splatmaps[2] = { splatmap1, splatmap2 };
Array<Color32> splatmapData;
TextureDataResult data1;
const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches);
const float heightmapSizeInv = 1.0f / (heightmapSize - 1);
for (int32 index = 0; index < ARRAY_COUNT(splatmaps); index++)
{
const auto splatmap = splatmaps[index];
if (!splatmap)
continue;
// Prepare data
if (splatmapData.IsEmpty())
splatmapData.Resize(heightmapSize * heightmapSize);
// Get splatmap data
if (GetTextureDataForSampling(splatmap, data1))
return true;
const auto sampler = PixelFormatSampler::Get(data1.Format);
// Modify heightmap splatmaps with sub-range of the input splatmaps
splatmapData.Resize(heightmapSize * heightmapSize);
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{
auto patch = terrain->GetPatch(patchIndex);
const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
// Sample splatmap pixels with interpolation to get actual splatmap values
for (int32 z = 0; z < heightmapSize; z++)
{
for (int32 x = 0; x < heightmapSize; x++)
{
const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Color color = sampler->SampleLinear(data1.Mip0DataPtr->Get(), uv, data1.Mip0Size, data1.RowPitch);
Color32 layers;
@@ -374,63 +367,38 @@ Color32* TerrainTools::GetSplatMapData(Terrain* terrain, const Int2& patchCoord,
bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
{
PROFILE_CPU_NAMED("Terrain.ExportTerrain");
CHECK_RETURN(terrain && terrain->GetPatchesCount() != 0, true);
const auto firstPatch = terrain->GetPatch(0);
// Calculate texture size
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount;
// Find size of heightmap in patches
const auto firstPatch = terrain->GetPatch(0);
Int2 start(firstPatch->GetX(), firstPatch->GetZ());
Int2 end(start);
for (int32 i = 0; i < terrain->GetPatchesCount(); i++)
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{
const int32 x = terrain->GetPatch(i)->GetX();
const int32 y = terrain->GetPatch(i)->GetZ();
if (x < start.X)
start.X = x;
if (y < start.Y)
start.Y = y;
if (x > end.X)
end.X = x;
if (y > end.Y)
end.Y = y;
const auto patch = terrain->GetPatch(patchIndex);
const Int2 pos(patch->GetX(), patch->GetZ());
start = Int2::Min(start, pos);
end = Int2::Max(end, pos);
}
const Int2 size = (end + 1) - start;
// Allocate - with space for non-existent patches
// Allocate heightmap for a whole terrain (NumberOfPatches * 4x4 * ChunkSize + 1)
const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1;
Array<float> heightmap;
heightmap.Resize(patchVertexCount * size.X * size.Y);
// Set to any element, where: min < elem < max
heightmap.Resize(heightmapSize.X * heightmapSize.Y);
heightmap.SetAll(firstPatch->GetHeightmapData()[0]);
const int32 heightmapWidth = patchEdgeVertexCount * size.X;
// Fill heightmap with data
// Fill heightmap with data from all patches
const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{
// Pick a patch
const auto patch = terrain->GetPatch(patchIndex);
const float* data = patch->GetHeightmapData();
// Beginning of patch
int32 dstIndex = (patch->GetX() - start.X) * patchEdgeVertexCount +
(patch->GetZ() - start.Y) * size.Y * patchVertexCount;
// Iterate over lines in patch
for (int32 z = 0; z < patchEdgeVertexCount; z++)
{
// Iterate over vertices in line
for (int32 x = 0; x < patchEdgeVertexCount; x++)
{
heightmap[dstIndex + x] = data[z * patchEdgeVertexCount + x];
}
dstIndex += heightmapWidth;
}
const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y);
const float* src = patch->GetHeightmapData();
float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1);
for (int32 row = 0; row < rowSize; row++)
Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float));
}
// Interpolate to 16-bit int
@@ -438,44 +406,42 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
maxHeight = minHeight = heightmap[0];
for (int32 i = 1; i < heightmap.Count(); i++)
{
float h = heightmap[i];
float h = heightmap.Get()[i];
if (maxHeight < h)
maxHeight = h;
else if (minHeight > h)
minHeight = h;
}
const float maxValue = 65535.0f;
const float alpha = maxValue / (maxHeight - minHeight);
const float alpha = MAX_uint16 / (maxHeight - minHeight);
// Storage for pixel data
Array<uint16> byteHeightmap(heightmap.Capacity());
for (auto& elem : heightmap)
Array<uint16> byteHeightmap;
byteHeightmap.Resize(heightmap.Count());
for (int32 i = 0; i < heightmap.Count(); i++)
{
byteHeightmap.Add(static_cast<uint16>(alpha * (elem - minHeight)));
float height = heightmap.Get()[i];
byteHeightmap.Get()[i] = static_cast<uint16>(alpha * (height - minHeight));
}
// Create texture
TextureData textureData;
textureData.Height = textureData.Width = heightmapWidth;
textureData.Width = heightmapSize.X;
textureData.Height = heightmapSize.Y;
textureData.Depth = 1;
textureData.Format = PixelFormat::R16_UNorm;
textureData.Items.Resize(1);
textureData.Items[0].Mips.Resize(1);
// Fill mip data
TextureMipData* srcMip = textureData.GetData(0, 0);
srcMip->Data.Link(byteHeightmap.Get());
srcMip->Lines = textureData.Height;
srcMip->RowPitch = textureData.Width * 2; // 2 bytes per pixel for format R16
srcMip->RowPitch = textureData.Width * sizeof(uint16);
srcMip->DepthPitch = srcMip->Lines * srcMip->RowPitch;
// Find next non-existing file heightmap file
FileSystem::NormalizePath(outputFolder);
const String baseFileName(TEXT("heightmap"));
String outputPath;
for (int32 i = 0; i < MAX_int32; i++)
for (int32 i = 0; i < 100; i++)
{
outputPath = outputFolder / baseFileName + StringUtils::ToString(i) + TEXT(".png");
if (!FileSystem::FileExists(outputPath))

View File

@@ -212,6 +212,10 @@ namespace FlaxEditor.Utilities
if (value is FlaxEngine.Object)
return value;
// For custom types use interface
if (value is ICloneable clonable)
return clonable.Clone();
// For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor
if (value != null && (!value.GetType().IsValueType || !value.GetType().IsClass))
{
@@ -548,6 +552,26 @@ namespace FlaxEditor.Utilities
return arr;
}
internal static void StructureToByteArray(object value, int valueSize, IntPtr tempBuffer, byte[] dataBuffer)
{
var valueType = value.GetType();
if (valueType.IsEnum)
{
var ptr = FlaxEngine.Interop.NativeInterop.ValueTypeUnboxer.GetPointer(value, valueType);
FlaxEngine.Utils.MemoryCopy(tempBuffer, ptr, (ulong)valueSize);
}
else
Marshal.StructureToPtr(value, tempBuffer, true);
Marshal.Copy(tempBuffer, dataBuffer, 0, valueSize);
}
internal static object ByteArrayToStructure(IntPtr valuePtr, Type valueType, int valueSize)
{
if (valueType.IsEnum)
return FlaxEngine.Interop.NativeInterop.MarshalToManaged(valuePtr, valueType);
return Marshal.PtrToStructure(valuePtr, valueType);
}
internal static unsafe string ReadStr(this BinaryReader stream, int check)
{
int length = stream.ReadInt32();

View File

@@ -66,13 +66,14 @@ public:
ViewportIconsRendererService ViewportIconsRendererServiceInstance;
float ViewportIconsRenderer::Scale = 1.0f;
Real ViewportIconsRenderer::MinSize = 7.0f;
Real ViewportIconsRenderer::MaxSize = 30.0f;
Real ViewportIconsRenderer::MaxSizeDistance = 1000.0f;
void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds)
{
constexpr Real minSize = 7.0;
constexpr Real maxSize = 30.0;
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / 1000.0f);
Real radius = minSize + Math::Min<Real>(scale, 1.0f) * (maxSize - minSize);
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / MaxSizeDistance);
Real radius = MinSize + Math::Min<Real>(scale, 1.0f) * (MaxSize - MinSize);
bounds = BoundingSphere(position, radius * Scale);
}
@@ -88,6 +89,7 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor
draw.Flags = StaticFlags::Transform;
draw.DrawModes = DrawPass::Forward;
draw.PerInstanceRandom = 0;
draw.StencilValue = 0;
draw.LODBias = 0;
draw.ForcedLOD = -1;
draw.SortOrder = 0;

View File

@@ -22,6 +22,21 @@ public:
/// </summary>
API_FIELD() static float Scale;
/// <summary>
/// The minimum size of the icons.
/// </summary>
API_FIELD() static Real MinSize;
/// <summary>
/// The maximum size of the icons.
/// </summary>
API_FIELD() static Real MaxSize;
/// <summary>
/// The distance to the camera at which the icons will be drawn at their maximum size.
/// </summary>
API_FIELD() static Real MaxSizeDistance;
/// <summary>
/// Draws the icons for the actors in the given scene (or actor tree).
/// </summary>

View File

@@ -541,7 +541,7 @@ namespace FlaxEditor.Viewport
// Setup options
{
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
_editor.Options.OptionsChanged += OnEditorOptionsChanged;
SetupViewportOptions();
}
@@ -587,7 +587,7 @@ namespace FlaxEditor.Viewport
// Camera Settings Menu
var cameraCM = new ContextMenu();
_cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth)
_cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), _editor.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth)
{
Tag = this,
TooltipText = "Camera Settings",
@@ -596,7 +596,7 @@ namespace FlaxEditor.Viewport
_cameraWidget.Parent = this;
// Orthographic/Perspective Mode Widget
_orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true)
_orthographicModeButton = new ViewportWidgetButton(string.Empty, _editor.Icons.CamSpeed32, null, true)
{
Checked = !_isOrtho,
TooltipText = "Toggle Orthographic/Perspective Mode",
@@ -869,8 +869,8 @@ namespace FlaxEditor.Viewport
{
}
});
viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = Editor.Instance.Icons.Rotate32;
viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0)).Icon = Editor.Instance.Icons.Rotate32;
viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = _editor.Icons.Rotate32;
viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0));
viewLayers.AddSeparator();
var layers = LayersAndTagsSettings.GetCurrentLayers();
if (layers != null && layers.Length > 0)
@@ -910,8 +910,8 @@ namespace FlaxEditor.Viewport
{
}
});
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = _editor.Icons.Rotate32;
viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None);
viewFlags.AddSeparator();
for (int i = 0; i < ViewFlagsValues.Length; i++)
{
@@ -1091,7 +1091,7 @@ namespace FlaxEditor.Viewport
/// </summary>
private void SetupViewportOptions()
{
var options = Editor.Instance.Options.Options;
var options = _editor.Options.Options;
_minMovementSpeed = options.Viewport.MinMovementSpeed;
MovementSpeed = options.Viewport.MovementSpeed;
_maxMovementSpeed = options.Viewport.MaxMovementSpeed;
@@ -1298,6 +1298,11 @@ namespace FlaxEditor.Viewport
_mouseSensitivity = options.Viewport.MouseSensitivity;
_maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps;
_cameraEasingDegree = options.Viewport.CameraEasingDegree;
ViewportIconsRenderer.MinSize = options.Viewport.IconsMinimumSize;
ViewportIconsRenderer.MaxSize = options.Viewport.IconsMaximumSize;
ViewportIconsRenderer.MaxSizeDistance = options.Viewport.MaxSizeDistance;
OnCameraMovementProgressChanged();
}
@@ -1711,7 +1716,7 @@ namespace FlaxEditor.Viewport
// Check if update mouse
var size = Size;
var options = Editor.Instance.Options.Options;
var options = _editor.Options.Options;
if (_isControllingMouse)
{
var rmbWheel = false;
@@ -1952,7 +1957,7 @@ namespace FlaxEditor.Viewport
return true;
// Custom input events
return InputActions.Process(Editor.Instance, this, key);
return InputActions.Process(_editor, this, key);
}
/// <inheritdoc />
@@ -1969,7 +1974,7 @@ namespace FlaxEditor.Viewport
base.Draw();
// Add overlay during debugger breakpoint hang
if (Editor.Instance.Simulation.IsDuringBreakpointHang)
if (_editor.Simulation.IsDuringBreakpointHang)
{
var bounds = new Rectangle(Float2.Zero, Size);
Render2D.FillRectangle(bounds, new Color(0.0f, 0.0f, 0.0f, 0.2f));
@@ -1994,7 +1999,7 @@ namespace FlaxEditor.Viewport
/// <inheritdoc />
public override void OnDestroy()
{
Editor.Instance.Options.OptionsChanged -= OnEditorOptionsChanged;
_editor.Options.OptionsChanged -= OnEditorOptionsChanged;
base.OnDestroy();
}

View File

@@ -6,6 +6,8 @@ using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Modules;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Cameras;
@@ -13,6 +15,7 @@ using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Viewport
@@ -70,8 +73,11 @@ namespace FlaxEditor.Viewport
private PrefabUIEditorRoot _uiRoot;
private bool _showUI = false;
private int _defaultScaleActiveIndex = 0;
private int _customScaleActiveIndex = -1;
private ContextMenuButton _uiModeButton;
private ContextMenuChildMenu _uiViewOptions;
/// <summary>
/// Event fired when the UI Mode is toggled.
@@ -137,6 +143,8 @@ namespace FlaxEditor.Viewport
UseAutomaticTaskManagement = defaultFeatures;
ShowDefaultSceneActors = defaultFeatures;
TintColor = defaultFeatures ? Color.White : Color.Transparent;
if (_uiViewOptions != null)
_uiViewOptions.Visible = _showUI;
UIModeToggled?.Invoke(_showUI);
}
}
@@ -210,7 +218,7 @@ namespace FlaxEditor.Viewport
_uiParentLink = _uiRoot.UIRoot;
// UI mode buton
_uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", (button) => ShowUI = button.Checked);
_uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", button => ShowUI = button.Checked);
_uiModeButton.AutoCheck = true;
_uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI;
@@ -222,6 +230,91 @@ namespace FlaxEditor.Viewport
SetUpdate(ref _update, OnUpdate);
}
/// <summary>
/// Creates the view scaling options. Needs to be called after a Prefab is valid and loaded.
/// </summary>
public void CreateViewScalingOptions()
{
if (_uiViewOptions != null)
return;
_uiViewOptions = ViewWidgetButtonMenu.AddChildMenu("UI View Scaling");
_uiViewOptions.Visible = _showUI;
LoadCustomUIScalingOption();
Editor.Instance.UI.CreateViewportSizingContextMenu(_uiViewOptions.ContextMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, true, ChangeUIView, (a, b) =>
{
_defaultScaleActiveIndex = a;
_customScaleActiveIndex = b;
});
}
private void ChangeUIView(UIModule.ViewportScaleOption uiViewScaleOption)
{
_uiRoot.SetViewSize((Float2)uiViewScaleOption.Size);
}
/// <summary>
/// Saves the active ui scaling option.
/// </summary>
public void SaveActiveUIScalingOption()
{
if (!Prefab)
return;
var id = Prefab.ID;
var defaultKey = $"{id}:DefaultViewportScalingIndex";
Editor.Instance.ProjectCache.SetCustomData(defaultKey, _defaultScaleActiveIndex.ToString());
var customKey = $"{id}:CustomViewportScalingIndex";
Editor.Instance.ProjectCache.SetCustomData(customKey, _customScaleActiveIndex.ToString());
}
private void LoadCustomUIScalingOption()
{
if (!Prefab)
return;
var id = Prefab.ID;
Prefab.WaitForLoaded();
var defaultKey = $"{id}:DefaultViewportScalingIndex";
if (Editor.Instance.ProjectCache.TryGetCustomData(defaultKey, out string defaultData))
{
if (int.TryParse(defaultData, out var index))
{
var options = Editor.Instance.UI.DefaultViewportScaleOptions;
if (options.Count > index)
{
_defaultScaleActiveIndex = index;
if (index != -1)
ChangeUIView(Editor.Instance.UI.DefaultViewportScaleOptions[index]);
}
// Assume option does not exist anymore so move to default.
else if (index != -1)
{
_defaultScaleActiveIndex = 0;
}
}
}
var customKey = $"{id}:CustomViewportScalingIndex";
if (Editor.Instance.ProjectCache.TryGetCustomData(customKey, out string data))
{
if (int.TryParse(data, out var index))
{
var options = Editor.Instance.UI.CustomViewportScaleOptions;
if (options.Count > index)
{
_customScaleActiveIndex = index;
if (index != -1)
ChangeUIView(options[index]);
}
// Assume option does not exist anymore so move to default.
else if (index != -1)
{
_defaultScaleActiveIndex = 0;
_customScaleActiveIndex = -1;
}
}
}
}
private void OnUpdate(float deltaTime)
{
for (int i = 0; i < Gizmos.Count; i++)

View File

@@ -112,8 +112,9 @@ namespace FlaxEditor.Viewport.Previews
LinkCanvas(_instance);
// Link UI control to the preview
var uiControl = _instance as UIControl;
if (_uiControlLinked == null &&
_instance is UIControl uiControl &&
uiControl != null &&
uiControl.Control != null &&
uiControl.Control.Parent == null)
{
@@ -128,6 +129,12 @@ namespace FlaxEditor.Viewport.Previews
_uiControlLinked.Control.Parent = _uiParentLink;
_hasUILinked = true;
}
// Use UI mode when root is empty UI Control
if (_uiControlLinked == null && uiControl != null && uiControl.Control == null)
{
_hasUILinked = true;
}
}
private void LinkCanvas(Actor actor)

View File

@@ -97,6 +97,7 @@ namespace FlaxEditor.Windows
"Jean-Baptiste Perrier",
"Chandler Cox",
"Ari Vuollet",
"Vincent Saarmann",
});
authors.Sort();
var authorsLabel = new Label(4, topParentControl.Bottom + 20, Width - 8, 70)

View File

@@ -371,6 +371,7 @@ namespace FlaxEditor.Windows.Assets
else
_viewport.SetInitialUIMode(_viewport._hasUILinked);
_viewport.UIModeToggled += OnUIModeToggled;
_viewport.CreateViewScalingOptions();
Graph.MainActor = _viewport.Instance;
Selection.Clear();
Select(Graph.Main);
@@ -567,6 +568,15 @@ namespace FlaxEditor.Windows.Assets
Graph.Dispose();
}
/// <inheritdoc />
protected override void OnClose()
{
// Save current UI view size state.
_viewport.SaveActiveUIScalingOption();
base.OnClose();
}
/// <inheritdoc />
public EditorViewport PresenterViewport => _viewport;

View File

@@ -116,6 +116,11 @@ namespace FlaxEditor.Windows
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.VisualScriptDebuggerWin.FocusOrShow();
});
InputActions.Add(options => options.EditorOptionsWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.EditorOptionsWin.FocusOrShow();
});
// Register
Editor.Windows.OnWindowAdd(this);

View File

@@ -6,6 +6,7 @@ using System.Xml;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Modules;
using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -34,8 +35,8 @@ namespace FlaxEditor.Windows
private CursorLockMode _cursorLockMode = CursorLockMode.None;
// Viewport scaling variables
private List<ViewportScaleOptions> _defaultViewportScaling = new List<ViewportScaleOptions>();
private List<ViewportScaleOptions> _customViewportScaling = new List<ViewportScaleOptions>();
private int _defaultScaleActiveIndex = 0;
private int _customScaleActiveIndex = -1;
private float _viewportAspectRatio = 1;
private float _windowAspectRatio = 1;
private bool _useAspect = false;
@@ -246,35 +247,6 @@ namespace FlaxEditor.Windows
/// </summary>
public InterfaceOptions.PlayModeFocus FocusOnPlayOption { get; set; }
private enum ViewportScaleType
{
Resolution = 0,
Aspect = 1,
}
private class ViewportScaleOptions
{
/// <summary>
/// The name.
/// </summary>
public string Label;
/// <summary>
/// The Type of scaling to do.
/// </summary>
public ViewportScaleType ScaleType;
/// <summary>
/// The width and height to scale by.
/// </summary>
public Int2 Size;
/// <summary>
/// If the scaling is active.
/// </summary>
public bool Active;
}
private class PlayModeFocusOptions
{
/// <summary>
@@ -420,7 +392,7 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand());
}
private void ChangeViewportRatio(ViewportScaleOptions v)
private void ChangeViewportRatio(UIModule.ViewportScaleOption v)
{
if (v == null)
return;
@@ -439,11 +411,11 @@ namespace FlaxEditor.Windows
{
switch (v.ScaleType)
{
case ViewportScaleType.Aspect:
case UIModule.ViewportScaleOption.ViewportScaleType.Aspect:
_useAspect = true;
_freeAspect = false;
break;
case ViewportScaleType.Resolution:
case UIModule.ViewportScaleOption.ViewportScaleType.Resolution:
_useAspect = false;
_freeAspect = false;
break;
@@ -634,49 +606,12 @@ namespace FlaxEditor.Windows
// Viewport aspect ratio
{
// Create default scaling options if they dont exist from deserialization.
if (_defaultViewportScaling.Count == 0)
{
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "Free Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(1, 1),
Active = true,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "16:9 Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(16, 9),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "16:10 Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(16, 10),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "1920x1080 Resolution (Full HD)",
ScaleType = ViewportScaleType.Resolution,
Size = new Int2(1920, 1080),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "2560x1440 Resolution (2K)",
ScaleType = ViewportScaleType.Resolution,
Size = new Int2(2560, 1440),
Active = false,
});
}
var vsMenu = menu.AddChildMenu("Viewport Size").ContextMenu;
CreateViewportSizingContextMenu(vsMenu);
Editor.UI.CreateViewportSizingContextMenu(vsMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, false, ChangeViewportRatio, (a, b) =>
{
_defaultScaleActiveIndex = a;
_customScaleActiveIndex = b;
});
}
// Take Screenshot
@@ -774,243 +709,6 @@ namespace FlaxEditor.Windows
}
}
private void CreateViewportSizingContextMenu(ContextMenu vsMenu)
{
// Add default viewport sizing options
for (int i = 0; i < _defaultViewportScaling.Count; i++)
{
var viewportScale = _defaultViewportScaling[i];
var button = vsMenu.AddButton(viewportScale.Label);
button.CloseMenuOnClick = false;
button.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
button.Tag = viewportScale;
if (viewportScale.Active)
ChangeViewportRatio(viewportScale);
button.Clicked += () =>
{
if (button.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v)
{
if (cmb == button)
{
v.Active = true;
button.Icon = Style.Current.CheckBoxTick;
ChangeViewportRatio(v);
}
else if (v.Active)
{
cmb.Icon = SpriteHandle.Invalid;
v.Active = false;
}
}
}
};
}
if (_defaultViewportScaling.Count != 0)
vsMenu.AddSeparator();
// Add custom viewport options
for (int i = 0; i < _customViewportScaling.Count; i++)
{
var viewportScale = _customViewportScaling[i];
var childCM = vsMenu.AddChildMenu(viewportScale.Label);
childCM.CloseMenuOnClick = false;
childCM.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
childCM.Tag = viewportScale;
if (viewportScale.Active)
ChangeViewportRatio(viewportScale);
var applyButton = childCM.ContextMenu.AddButton("Apply");
applyButton.Tag = childCM.Tag = viewportScale;
applyButton.CloseMenuOnClick = false;
applyButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v)
{
if (child == childCM)
{
v.Active = true;
childCM.Icon = Style.Current.CheckBoxTick;
ChangeViewportRatio(v);
}
else if (v.Active)
{
cmb.Icon = SpriteHandle.Invalid;
v.Active = false;
}
}
}
};
var deleteButton = childCM.ContextMenu.AddButton("Delete");
deleteButton.CloseMenuOnClick = false;
deleteButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
var v = (ViewportScaleOptions)childCM.Tag;
if (v.Active)
{
v.Active = false;
_defaultViewportScaling[0].Active = true;
ChangeViewportRatio(_defaultViewportScaling[0]);
}
_customViewportScaling.Remove(v);
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu);
vsMenu.PerformLayout();
};
}
if (_customViewportScaling.Count != 0)
vsMenu.AddSeparator();
// Add button
var add = vsMenu.AddButton("Add...");
add.CloseMenuOnClick = false;
add.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(add, new Float2(add.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var typeLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Type",
HorizontalAlignment = TextAlignment.Near,
};
typeLabel.LocalX += 10;
typeLabel.LocalY += 35;
var typeDropdown = new Dropdown
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Items = { "Aspect", "Resolution" },
SelectedItem = "Aspect",
Width = nameTextBox.Width
};
typeDropdown.LocalY += 35;
typeDropdown.LocalX += 100;
var whLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Width & Height",
HorizontalAlignment = TextAlignment.Near,
};
whLabel.LocalX += 10;
whLabel.LocalY += 60;
var wValue = new IntValueBox(16)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
wValue.LocalY += 60;
wValue.LocalX += 100;
var hValue = new IntValueBox(9)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
hValue.LocalY += 60;
hValue.LocalX += 165;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Submit",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleType type);
var combineString = type == ViewportScaleType.Aspect ? ":" : "x";
var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem;
var newViewportOption = new ViewportScaleOptions
{
ScaleType = type,
Label = name,
Size = new Int2(wValue.Value, hValue.Value),
};
_customViewportScaling.Add(newViewportOption);
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu);
vsMenu.PerformLayout();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
typeDropdown.SelectedItem = "Aspect";
hValue.Value = 9;
wValue.Value = 16;
popup.Hide();
};
};
}
/// <inheritdoc />
public override void Draw()
{
@@ -1191,12 +889,12 @@ namespace FlaxEditor.Windows
if (!_cursorVisible)
Screen.CursorVisible = true;
Screen.CursorLock = CursorLockMode.None;
}
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
{
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
{
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
}
}
}
@@ -1237,8 +935,8 @@ namespace FlaxEditor.Windows
writer.WriteAttributeString("ShowGUI", ShowGUI.ToString());
writer.WriteAttributeString("EditGUI", EditGUI.ToString());
writer.WriteAttributeString("ShowDebugDraw", ShowDebugDraw.ToString());
writer.WriteAttributeString("DefaultViewportScaling", JsonSerializer.Serialize(_defaultViewportScaling));
writer.WriteAttributeString("CustomViewportScaling", JsonSerializer.Serialize(_customViewportScaling));
writer.WriteAttributeString("DefaultViewportScalingIndex", _defaultScaleActiveIndex.ToString());
writer.WriteAttributeString("CustomViewportScalingIndex", _customScaleActiveIndex.ToString());
}
/// <inheritdoc />
@@ -1250,22 +948,30 @@ namespace FlaxEditor.Windows
EditGUI = value1;
if (bool.TryParse(node.GetAttribute("ShowDebugDraw"), out value1))
ShowDebugDraw = value1;
if (node.HasAttribute("CustomViewportScaling"))
_customViewportScaling = JsonSerializer.Deserialize<List<ViewportScaleOptions>>(node.GetAttribute("CustomViewportScaling"));
if (int.TryParse(node.GetAttribute("DefaultViewportScalingIndex"), out int value2))
_defaultScaleActiveIndex = value2;
if (int.TryParse(node.GetAttribute("CustomViewportScalingIndex"), out value2))
_customScaleActiveIndex = value2;
for (int i = 0; i < _customViewportScaling.Count; i++)
if (_defaultScaleActiveIndex != -1)
{
if (_customViewportScaling[i].Active)
ChangeViewportRatio(_customViewportScaling[i]);
var options = Editor.UI.DefaultViewportScaleOptions;
if (options.Count > _defaultScaleActiveIndex)
ChangeViewportRatio(options[_defaultScaleActiveIndex]);
else
_defaultScaleActiveIndex = 0;
}
if (node.HasAttribute("DefaultViewportScaling"))
_defaultViewportScaling = JsonSerializer.Deserialize<List<ViewportScaleOptions>>(node.GetAttribute("DefaultViewportScaling"));
for (int i = 0; i < _defaultViewportScaling.Count; i++)
if (_customScaleActiveIndex != -1)
{
if (_defaultViewportScaling[i].Active)
ChangeViewportRatio(_defaultViewportScaling[i]);
var options = Editor.UI.CustomViewportScaleOptions;
if (options.Count > _customScaleActiveIndex)
ChangeViewportRatio(options[_customScaleActiveIndex]);
else
{
_defaultScaleActiveIndex = 0;
_customScaleActiveIndex = -1;
}
}
}

View File

@@ -246,7 +246,7 @@ namespace FlaxEditor.Windows
});
var flags = DebugCommands.GetCommandFlags(command);
if (flags.HasFlag(DebugCommands.CommandFlags.Exec))
lastItem.TintColor = new Color(0.85f, 0.85f, 1.0f, 1.0f);
lastItem.TintColor = new Color(0.75f, 0.75f, 1.0f, 1.0f);
else if (flags.HasFlag(DebugCommands.CommandFlags.Read) && !flags.HasFlag(DebugCommands.CommandFlags.Write))
lastItem.TintColor = new Color(0.85f, 0.85f, 0.85f, 1.0f);
lastItem.Focused += item =>
@@ -320,12 +320,25 @@ namespace FlaxEditor.Windows
// Show commands search popup based on current text input
var text = Text.Trim();
if (text.Length != 0)
bool isWhitespaceOnly = string.IsNullOrWhiteSpace(Text) && !string.IsNullOrEmpty(Text);
if (text.Length != 0 || isWhitespaceOnly)
{
DebugCommands.Search(text, out var matches);
if (matches.Length != 0)
if (matches.Length != 0 || isWhitespaceOnly)
{
ShowPopup(ref _searchPopup, matches, text);
string[] commands = [];
if (isWhitespaceOnly)
DebugCommands.GetAllCommands(out commands);
ShowPopup(ref _searchPopup, isWhitespaceOnly ? commands : matches, text);
if (isWhitespaceOnly)
{
// Scroll to and select first item for consistent behaviour
var firstItem = _searchPopup.ItemsPanel.Children[0] as Item;
_searchPopup.ScrollToAndHighlightItemByName(firstItem.Name);
}
return;
}
}

View File

@@ -93,6 +93,7 @@ void MultiBlendBucketInit(AnimGraphInstanceData::Bucket& bucket)
void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket)
{
bucket.BlendPose.TransitionPosition = 0.0f;
bucket.BlendPose.BlendPoseIndex = -1;
bucket.BlendPose.PreviousBlendPoseIndex = -1;
}

View File

@@ -239,7 +239,8 @@ public:
struct BlendPoseBucket
{
float TransitionPosition;
int32 PreviousBlendPoseIndex;
int16 BlendPoseIndex;
int16 PreviousBlendPoseIndex;
};
struct StateMachineBucket
@@ -810,6 +811,7 @@ public:
{
// Copy the node transformations
Platform::MemoryCopy(dstNodes->Nodes.Get(), srcNodes->Nodes.Get(), sizeof(Transform) * _skeletonNodesCount);
dstNodes->RootMotion = srcNodes->RootMotion;
// Copy the animation playback state
dstNodes->Position = srcNodes->Position;

View File

@@ -676,9 +676,12 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const
if (!ANIM_GRAPH_IS_VALID_PTR(poseB))
nodesB = GetEmptyNodes();
const Transform* srcA = nodesA->Nodes.Get();
const Transform* srcB = nodesB->Nodes.Get();
Transform* dst = nodes->Nodes.Get();
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{
Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
Transform::Lerp(srcA[i], srcB[i], alpha, dst[i]);
}
Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion);
nodes->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha);
@@ -1263,21 +1266,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
{
const auto valueA = tryGetValue(node->GetBox(1), Value::Null);
const auto valueB = tryGetValue(node->GetBox(2), Value::Null);
const auto nodes = node->GetNodes(this);
auto nodesA = static_cast<AnimGraphImpulse*>(valueA.AsPointer);
auto nodesB = static_cast<AnimGraphImpulse*>(valueB.AsPointer);
if (!ANIM_GRAPH_IS_VALID_PTR(valueA))
nodesA = GetEmptyNodes();
if (!ANIM_GRAPH_IS_VALID_PTR(valueB))
nodesB = GetEmptyNodes();
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{
Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
}
Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion);
value = nodes;
value = Blend(node, valueA, valueB, alpha, AlphaBlendMode::Linear);
}
break;
@@ -1758,35 +1747,38 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
// [2]: int Pose Count
// [3]: AlphaBlendMode Mode
// Prepare
auto& bucket = context.Data->State[node->BucketIndex].BlendPose;
const int32 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]);
const int16 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]);
const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]);
const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses);
const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt;
// Skip if nothing to blend
if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
{
break;
// Check if swap transition end points
if (bucket.PreviousBlendPoseIndex == poseIndex && bucket.BlendPoseIndex != poseIndex && bucket.TransitionPosition >= ANIM_GRAPH_BLEND_THRESHOLD)
{
bucket.TransitionPosition = blendDuration - bucket.TransitionPosition;
Swap(bucket.BlendPoseIndex, bucket.PreviousBlendPoseIndex);
}
// Check if transition is not active (first update, pose not changing or transition ended)
bucket.TransitionPosition += context.DeltaTime;
bucket.BlendPoseIndex = poseIndex;
if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD)
{
bucket.TransitionPosition = 0.0f;
bucket.BlendPoseIndex = poseIndex;
bucket.PreviousBlendPoseIndex = poseIndex;
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null);
break;
}
ASSERT(bucket.PreviousBlendPoseIndex >= 0 && bucket.PreviousBlendPoseIndex < poseCount);
// Blend two animations
{
const float alpha = bucket.TransitionPosition / blendDuration;
const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null);
const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null);
value = Blend(node, valueA, valueB, alpha, mode);
}

View File

@@ -23,11 +23,11 @@ void AudioListener::Update()
{
// Update the velocity
const Vector3 pos = GetPosition();
const float dt = Time::Update.UnscaledDeltaTime.GetTotalSeconds();
const float dt = Math::Max(Time::Update.UnscaledDeltaTime.GetTotalSeconds(), 0.00001f);
const auto prevVelocity = _velocity;
_velocity = (pos - _prevPos) / dt;
_prevPos = pos;
if (_velocity != prevVelocity)
if (_velocity != prevVelocity && !_velocity.IsNanOrInfinity())
{
AudioBackend::Listener::VelocityChanged(_velocity);
}

Some files were not shown because too many files have changed in this diff Show More