105 Commits

Author SHA1 Message Date
Chris Galvan c1d7294c5b Merge pull request #7120 from aws-lumberyard-dev/cgalvan/gitflow_220124_o3de_main
Merged `stabilization/2111RTE` to `main`
2022-01-27 12:07:39 -06:00
Chris Galvan acc2346678 Merge remote-tracking branch 'upstream/stabilization/2111RTE' into cgalvan/gitflow_220124_o3de_main
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2022-01-24 13:13:43 -06:00
Alex Peterson 1909e5fa54 Handle case where engine.json missing or corrupt (#7049)
Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com>
2022-01-21 13:09:09 -08:00
Tom Hulton-Harrop 93358dcbeb Cherry-pick of PR-6700 - Updates to ViewportTitleDlg to better expose grid snapping visualization (#6997)
* cherry-pick of PR 6700

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* revert title dialog look to old style

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
2022-01-21 09:19:53 +00:00
AMZN-Phil 0bddc1a826 Merge pull request #6429 from aws-lumberyard-dev/Prism/InstallerBuildNumCP
Cherry pick changes to 2111RTE for installer version build number
2022-01-20 10:33:32 -08:00
Alex Peterson 66f0f1cf5a Duplicate engine detection and help in Project Manager (#6984)
Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com>
2022-01-19 17:55:05 -08:00
Chris Galvan c7284a781e Merge pull request #6365 from aws-lumberyard-dev/Atom/guthadam/materialcomponent/workaround_for_lost_image_overrides_with_prefabs
Temporary fix for material component losing image overrides with prefabs
2022-01-04 11:28:39 -06:00
hershey5045 d7dc257927 Add MainPipeline to pass hierarchy for when HDR color grading component requests for the lut generation's image attachment. (#6436)
Signed-off-by: hershey5045 <43485729+hershey5045@users.noreply.github.com>
2021-12-16 12:07:37 -08:00
amzn-sj fc3c5fbd09 [Mac] Fix build error in (#6410)
Signed-off-by: amzn-sj <srikkant@amazon.com>
2021-12-16 09:43:00 -08:00
Qing Tao 94ddafc7a2 Atom/qingtao/image builder fixes (#6432)
* LYN-8837 o3de Material Editor - Texture Settings Editor - Hangs when converting texture (#6359)

Fixed a editor hanging issue when preview texture with astc format (starts multiple job threads inside a job thread)
Fixed an issue of changing texture setting didn't trigger image re-process.
Fixed an issue with image asset which has texture setting may have dependency with wrong preset
Added a EIF_HDR for source image in hdr format.
Fixed astc compression issue which may wrongly compress image to HDR astc format

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
(cherry picked from commit d9f0a3012d)

* ATOM-16958 [Image Builder] Alpha data would be removed for source image with alpha content (#6412)

Fixed a regression issue with image builder which it can choose proper preset for images with alpha content.

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
(cherry picked from commit b640f6d691)
2021-12-16 09:19:44 -08:00
moudgils fb36145e2e Rte fixes for stability (#6434)
* Fixed SRG updated related crash

Signed-off-by: moudgils <47460854+moudgils@users.noreply.github.com>

* Fixed SRG compile issue with metal which leads to multiple gpu crashes inlucde ImGuiPass render crash (#6315)

Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>

Co-authored-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
2021-12-15 18:35:17 -08:00
AMZN-Phil 58b6a9c1ac Merge pull request #6427 from aws-lumberyard-dev/Prism/GeneratorFix
Add a missing comma to fix generator
2021-12-15 16:05:30 -08:00
AMZN-Phil 82af1e6870 Force a string check on the version numbers
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
2021-12-15 10:21:01 -08:00
AMZN-Phil 38c8d94156 Use version check to allow for a defined empty string to fail and greater to check build number is a number greater than 0
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
2021-12-15 10:20:48 -08:00
AMZN-Phil f44697fbf4 Check whether env variables are defined
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
2021-12-15 10:20:23 -08:00
Mike Chang c019fe8946 Add conditional to pull O3DE_BUILD_VERSION through environment var (#6096)
Signed-off-by: Mike Chang <changml@amazon.com>
2021-12-15 10:19:36 -08:00
AMZN-Phil 105524b7c0 Add a missing comma to fix generator
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
2021-12-15 09:29:40 -08:00
AMZN-Phil 2fa10d7e6a Merge pull request #6397 from aws-lumberyard-dev/Prism/PMVS2022Check
Force Project Manager to generate VS2019 projects on Windows
2021-12-14 12:46:35 -08:00
rgba16f a60fba5bec Change Vulkan RHI CommandList::SetStreamBuffers to not do 2 memory allocation per draw by using fixed_vector
Signed-off-by: rgba16f 82187279+rgba16f@users.noreply.github.com
2021-12-14 14:15:36 -06:00
Nicholas Van Sickle 7e5115114c Merge pull request #6403 from aws-lumberyard-dev/nvsickle/FixAmbiguousTypeSerialization
Ensure StoreTypeName stores the correct type for generic types
2021-12-14 10:41:19 -08:00
Tom Hulton-Harrop 197e7b95e1 Fix for change with axis gizmo labels not appearing (#6256) (#6387)
Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
2021-12-14 09:24:10 +00:00
Nicholas Van Sickle f71b134a84 Ensure JsonSerializer::StoreTypeName stores the correct type for generic types
Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
2021-12-13 23:40:35 -08:00
AMZN-Phil 98fa18558e Force Project Manager to use VS2019
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
2021-12-13 17:40:09 -08:00
carlitosan a2bb968371 Merge pull request #6345 from aws-lumberyard-dev/sc-editor-onto-rte-part4-6322
Sc editor onto rte part4 6322
2021-12-13 13:15:59 -08:00
rgba16f 2d13b648da Change Vulkan RHI CommandList::SetStreamBuffers to not do 2 memory allocation per draw by using fixed_vector
Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com>
2021-12-13 13:16:02 -06:00
carlitosan 0a1dc3c4bd Fix missing asset handler error on EditorSCComponent load from pre SourceHandle files
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:54 -08:00
carlitosan 837e532ad7 fail safe for EditorScriptCanvasComponents saved before AZ::IO::Path got json support
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:52 -08:00
carlitosan a5b30ffc5a fix interpreted statics
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:50 -08:00
carlitosan 9830925309 small fixes for SC play in editor and warnings
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:49 -08:00
carlitosan 0963bc0cc5 removed commented out include
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:47 -08:00
carlitosan dc538d94e5 update error window message and add AP launch request
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:45 -08:00
carlitosan cbc70b4b88 Add dialog window for messaging when SC assets fail to save
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:43 -08:00
carlitosan aeabf21bba clean up debug output settings
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:41 -08:00
carlitosan 0f07de7454 fix verbose setting
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:39 -08:00
carlitosan ac6c90cd2c pre-PR cleanup
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:37 -08:00
carlitosan 169416c2f9 remove testing code
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:35 -08:00
carlitosan d284d908b9 Make version explorer wait on AP for dependent assets
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:33 -08:00
carlitosan d8e5315199 Use weak reference for undo state, as it is an entirely internal class
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:31 -08:00
carlitosan b9bbe233be Restore undo/redo
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:29 -08:00
carlitosan 3e728d1183 fixed another string_view printf error caught by linux compiler
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:27 -08:00
carlitosan b10c679c33 fixed string_view printf error caught by linux compiler
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:25 -08:00
carlitosan 4f00718a38 fix linux build error, change translation system errors to warnings
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:23 -08:00
carlitosan 07bf8fc755 fix linux build error
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:21 -08:00
chcurran 0cc4c06213 remove uneeded files/comments
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:19 -08:00
chcurran d31c6a2774 remove uneeded files/comments
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:28:17 -08:00
carlitosan b0ef83e194 Delete $tmp29198_Test_LY_79396.scriptcanvas
Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com>
2021-12-13 10:27:50 -08:00
Guthrie Adams 3bca63bb71 Temporary fix for material component losing image overrides with prefabs
The bug reported that overridden texture properties would be lost whenever an entity was created, destroyed, or a prefab was created. Initially, it seemed like there was a problem with the custom JSON serializer for material properties. Debugging proved this to be incorrect because all of the data was converted to JSON values in the serializer on multiple passes. At some point during prefab patching, the data for the asset properties is lost while other values like colors and floats serialize correctly. Converting the asset data values into asset IDs resolves the immediate problem for the material component but the underlying issue is still under investigation by the prefab team. This change is being posted for review in case the underlying issue cannot be resolved in time for the next release.

Signed-off-by: Guthrie Adams <guthadam@amazon.com>

Fixing unittests and moving texture conversion into material component controller

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
2021-12-13 11:35:05 -06:00
lumberyard-employee-dm 40e1116e26 Use LegacySystemInterfaceCreated to initialize physics material library. (#6168) (#6347)
* Use LegacySystemInterfaceCreated to initialize physics material library. OnCatalogLoaded was used before but it's not called when running the editor without assets processed yet.

Signed-off-by: moraaar <moraaar@amazon.com>

Co-authored-by: moraaar <moraaar@amazon.com>
2021-12-13 12:10:36 +00:00
chcurran 87023cae47 finish last of pre-PR clean up, including saving over previsouly opened tabs
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:46 -08:00
chcurran 6421463df2 clean up WIP
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:46 -08:00
chcurran 2c107c364f fix mismatched file name on modification
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:45 -08:00
chcurran d8add36212 restore file save
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:45 -08:00
chcurran 499cdaae5e version upgrader in a presumed working story
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:44 -08:00
chcurran 55fa33cff4 Clean up modifier asset handling. Fix file handling string error.
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:44 -08:00
chcurran c4ea3075cc fixed unit tests bugs, removed commented out code, removed loading spam
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:43 -08:00
chcurran 8357fa34e9 fixed unit testing code
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:42 -08:00
chcurran 27cc659ab9 Editor Script Component simplified and working
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:42 -08:00
chcurran 66e744785f EditorCOmponent build pipeline WIP
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:41 -08:00
chcurran 23267fd862 SC Editor serialization update in JSON
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:41 -08:00
chcurran 5db535d1dd Merge branch 'sc-editor-asset-redux' of https://github.com/aws-lumberyard-dev/o3de into sc-editor-asset-redux 2021-12-10 11:56:40 -08:00
chcurran d9f849b03e File state change include external delete detection
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:40 -08:00
Chris Galvan 1797354560 Merge pull request #282 from aws-lumberyard-dev/cgalvan/SourceHandleCompleterFix
Fixed asset completer model for source handle picker.
2021-12-10 11:56:39 -08:00
Chris Galvan ca5424dd7b Fixed asset completer model for source handle picker.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:39 -08:00
Chris Galvan b44541c440 Merge pull request #281 from aws-lumberyard-dev/cgalvan/SCSourceFilePicker
Added property handler for SourceHandle type
2021-12-10 11:56:38 -08:00
chcurran 805bd8ef56 fix graph tab selection:
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:37 -08:00
Chris Galvan 31304ee9b1 Fixed issue when clearing out source handle property.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:37 -08:00
Chris Galvan c36d827fc5 Updated Script Canvas component to use source handle property.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:36 -08:00
Chris Galvan befd84cf0b Added property handler for SourceHandle type.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:36 -08:00
Chris Galvan b4407e5044 Made PropertyAssetCtrl more extensible.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:35 -08:00
Chris Galvan 42382cd8d1 Added logic to AssetPickerDialog to pre-select by file paths.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:35 -08:00
Chris Galvan d9ee02fddf Added method to AssetCompleterModel for specifying a filter directly.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:34 -08:00
Chris Galvan 231aaa5bf5 Added asset selection model option for a source asset type based on regex.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:33 -08:00
Chris Galvan 772cb30c57 Merge branch 'sc-editor-asset-redux' of https://github.com/aws-lumberyard-dev/o3de into cgalvan/SCSourceFilePicker 2021-12-10 11:56:33 -08:00
Chris Galvan 3f6824571f Added regular expression filter for asset browser entries.
Signed-off-by: Chris Galvan <chgalvan@amazon.com>
2021-12-10 11:56:32 -08:00
chcurran ad8cfa5f99 editor sc component switched over to source handle, not yet connected to file notifications
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:31 -08:00
chcurran b772db5e73 remove typo
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:30 -08:00
chcurran 727d1b3815 more aggressively release graph memory in version explorer
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:56:30 -08:00
chcurran 4342501804 fixed unit test running system
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:33 -08:00
chcurran f8fdf4b306 fixed version explorer issue
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:32 -08:00
chcurran 4484b69036 isolate the loading problem during version explorer
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:31 -08:00
chcurran 015185f9d6 fix upgrade scanner
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:31 -08:00
chcurran e34c6e55df fix scoped compile error
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:30 -08:00
chcurran b7d8c1a644 make default names NOT the default name of a previously existing file
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:30 -08:00
chcurran 921f675df2 restore source file deleted behavior
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:29 -08:00
chcurran d8e8cdba60 multi tab close fixed
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:28 -08:00
chcurran 5558be2aeb new source file close button works, but not on multiple tabs
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:27 -08:00
chcurran 6c1d1dc2e2 new source file button works
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:27 -08:00
chcurran 65814e65cc source file save-as
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:26 -08:00
chcurran 5cd8eb648c source save in place first pass
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:25 -08:00
chcurran 1ea245e46c source save asset-free WIP
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:24 -08:00
chcurran d40b9fc809 add file state for graphs
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:24 -08:00
chcurran 20147ddafb it renders!
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:23 -08:00
chcurran cbbd6df0c5 clean up open pipeline to render graph
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:22 -08:00
chcurran bc342df6b4 initial compile of detailed path of change to regular sc files
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:54:18 -08:00
chcurran c5cd854172 Git MainWindow.cpp to point where it compiles, and reveals the radius of changes for everything to work without assets
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:52:37 -08:00
chcurran 31c627defc initial scriptcanvas source handle
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
2021-12-10 11:52:36 -08:00
Alex Peterson 6613030fe6 Fix Visual Studio requirements text and doc link (#6312)
Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com>
2021-12-10 10:15:39 -08:00
srikappa-amzn ac03b6f50b Improve error messaging when duplicating entities before they are created (#4922) (#6279)
* Improved error messaging when user tries to duplicate before entities are created

Signed-off-by: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com>
2021-12-09 11:25:23 -08:00
Luis Sempé 667512c7ff Merge pull request #6233 from o3de/scripting/rte_02
Script Canvas node translation system and naming consistency
2021-12-08 13:39:25 -08:00
lumberyard-employee-dm cd65d8a5ac Pass relative path IsFileExcluded so that only paths relative to the root scan folder are matched against the exclude filters (#4504) (#6234)
* Pass relative path IsFileExcluded so that only paths relative to the root scan folder are matched against the exclude filters.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Revert previous change. Remove the exclude filter for the Install directory.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Pass in relative path to the exclude filter as before. Fix the AssetScanner tests.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Prepend a ./ to the relative path in order to match the exclude patterns

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Remove hack to prepend ./. Update the exclude patterns so that the hack is no longer required.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Add missing ? and remove whitespace

Signed-off-by: amzn-sj <srikkant@amazon.com>

* 1. IsFileExcluded() now converts the input path to a path that's relative to its corresponding scan folder.
2. Update regex patterns in gems and AutomatedTesting as well.
3. Remove unnecessary escaping for '/'.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Use ConvertToRelativePath() function to compute path relative to a scan folder.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* More fixes to regex patterns

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Remove test case which tests a hypothetical scenario that cannot occur. Fix another test case by adding scan folder.

Signed-off-by: amzn-sj <srikkant@amazon.com>

* Remove assert that's not needed since it's a valid scenario

Signed-off-by: amzn-sj <srikkant@amazon.com>

Co-authored-by: amzn-sj <srikkant@amazon.com>
2021-12-08 11:12:25 -06:00
lsemp3d 72bfd8bdf8 Script Canvas node translation system and naming consistency
Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com>
2021-12-07 15:40:04 -08:00
moraaar 8d096ebf61 Fixed critical json property. (#6205)
* Fixing critical tag as it needs a boolean, not a string.

Signed-off-by: moraaar <moraaar@amazon.com>

* Marking blast material library assets as criticals since it's necessary to be ready before the editor opens

Signed-off-by: moraaar <moraaar@amazon.com>
2021-12-07 16:44:45 +00:00
Mikhail Naumov c5615f812c Fixing pivot offset when performing undo on Transform component (#6150)
* Fixing undo offest on transform component

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>

* Fixining possible issue with firing an unnecessary OnTransformChanged event when entity is manually disabled/enabled

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>

* Adding better comments

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>

* Unit tests

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>

* Cherrupicking changes

Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>
2021-12-06 14:46:47 +00:00
moraaar dc8f9dc233 Add additional check to check material library is loaded when trying to retrieve names (#6165)
* Add additional check to ensure material library is loaded when trying to retrieve names.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Mark physmaterial assets as critical

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

Co-authored-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

Signed-off-by: moraaar moraaar@amazon.com
2021-12-06 13:26:23 +00:00
Chris Galvan 7b22bc64f3 Merge pull request #6044 from aws-lumberyard-dev/cgalvan/gitflow_211130_o3de_rte
Merged `stabilization/2110` to `stabilization/2111RTE`
2021-11-30 14:11:41 -06:00
1690 changed files with 240568 additions and 5437 deletions
@@ -3,19 +3,19 @@
"AssetProcessor": {
"Settings": {
"Exclude PythonTest Benchmark Settings Assets": {
"pattern": ".*\\\\/PythonTests\\\\/.*benchmarksettings"
"pattern": "(^|.+/)PythonTests/.*benchmarksettings"
},
"Exclude fbx_tests": {
"pattern": ".*\\\\/fbx_tests\\\\/assets\\\\/.*"
"pattern": "(^|.+/)fbx_tests/assets(/.+)$"
},
"Exclude wwise_bank_dependency_tests": {
"pattern": ".*\\\\/wwise_bank_dependency_tests\\\\/assets\\\\/.*"
"pattern": "(^|.+/)wwise_bank_dependency_tests/assets(/.+)$"
},
"Exclude AssetProcessorTestAssets": {
"pattern": ".*\\\\/asset_processor_tests\\\\/assets\\\\/.*"
"pattern": "(^|.+/)asset_processor_tests/assets(/.+)$"
},
"Exclude Restricted AssetProcessorTestAssets": {
"pattern": ".*\\\\/asset_processor_tests\\\\/restricted\\\\/.*"
"pattern": "(^|.+/)asset_processor_tests/restricted(/.+)$"
}
}
}
+40 -25
View File
@@ -229,25 +229,35 @@ void CViewportTitleDlg::SetupHelpersButton()
void CViewportTitleDlg::SetupOverflowMenu()
{
// Setup the overflow menu
QMenu* overFlowMenu = new QMenu(this);
// setup the overflow menu
auto overflowMenu = new QMenu(this);
m_audioMuteAction = new QAction("Mute Audio", overFlowMenu);
m_audioMuteAction = new QAction("Mute Audio", overflowMenu);
connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio);
overFlowMenu->addAction(m_audioMuteAction);
overflowMenu->addAction(m_audioMuteAction);
m_enableVRAction = new QAction("Enable VR Preview", overFlowMenu);
m_enableVRAction = new QAction("Enable VR Preview", overflowMenu);
connect(m_enableVRAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedEnableVR);
overFlowMenu->addAction(m_enableVRAction);
overflowMenu->addAction(m_enableVRAction);
overFlowMenu->addSeparator();
overflowMenu->addSeparator();
m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overFlowMenu);
m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overflowMenu);
connect(m_enableGridSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnGridSnappingToggled);
m_enableGridSnappingAction->setCheckable(true);
overFlowMenu->addAction(m_enableGridSnappingAction);
overflowMenu->addAction(m_enableGridSnappingAction);
m_gridSizeActionWidget = new QWidgetAction(overFlowMenu);
m_enableGridVisualizationAction = new QAction("Show Grid", overflowMenu);
connect(
m_enableGridVisualizationAction, &QAction::triggered,
[]
{
SandboxEditor::SetShowingGrid(!SandboxEditor::ShowingGrid());
});
m_enableGridVisualizationAction->setCheckable(true);
overflowMenu->addAction(m_enableGridVisualizationAction);
m_gridSizeActionWidget = new QWidgetAction(overflowMenu);
m_gridSpinBox = new AzQtComponents::DoubleSpinBox();
m_gridSpinBox->setValue(SandboxEditor::GridSnappingSize());
m_gridSpinBox->setMinimum(1e-2f);
@@ -257,31 +267,31 @@ void CViewportTitleDlg::SetupOverflowMenu()
m_gridSpinBox, QOverload<double>::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnGridSpinBoxChanged);
m_gridSizeActionWidget->setDefaultWidget(m_gridSpinBox);
overFlowMenu->addAction(m_gridSizeActionWidget);
overflowMenu->addAction(m_gridSizeActionWidget);
overFlowMenu->addSeparator();
overflowMenu->addSeparator();
m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overFlowMenu);
m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overflowMenu);
connect(m_enableAngleSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnAngleSnappingToggled);
m_enableAngleSnappingAction->setCheckable(true);
overFlowMenu->addAction(m_enableAngleSnappingAction);
overflowMenu->addAction(m_enableAngleSnappingAction);
m_angleSizeActionWidget = new QWidgetAction(overFlowMenu);
m_angleSizeActionWidget = new QWidgetAction(overflowMenu);
m_angleSpinBox = new AzQtComponents::DoubleSpinBox();
m_angleSpinBox->setValue(SandboxEditor::AngleSnappingSize());
m_angleSpinBox->setMinimum(1e-2f);
m_angleSpinBox->setToolTip(tr("Angle Snapping"));
m_angleSpinBox->setToolTip(tr("Angle size"));
QObject::connect(
m_angleSpinBox, QOverload<double>::of(&AzQtComponents::DoubleSpinBox::valueChanged), this,
&CViewportTitleDlg::OnAngleSpinBoxChanged);
m_angleSizeActionWidget->setDefaultWidget(m_angleSpinBox);
overFlowMenu->addAction(m_angleSizeActionWidget);
overflowMenu->addAction(m_angleSizeActionWidget);
m_ui->m_overflowBtn->setMenu(overFlowMenu);
m_ui->m_overflowBtn->setMenu(overflowMenu);
m_ui->m_overflowBtn->setPopupMode(QToolButton::InstantPopup);
connect(overFlowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState);
connect(overflowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState);
UpdateMuteActionText();
}
@@ -1004,31 +1014,36 @@ void CViewportTitleDlg::OnAngleSnappingToggled()
MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->trigger();
}
void CViewportTitleDlg::OnGridSpinBoxChanged(double value)
void CViewportTitleDlg::OnGridSpinBoxChanged(const double value)
{
SandboxEditor::SetGridSnappingSize(static_cast<float>(value));
SandboxEditor::SetGridSnappingSize(aznumeric_cast<float>(value));
}
void CViewportTitleDlg::OnAngleSpinBoxChanged(double value)
void CViewportTitleDlg::OnAngleSpinBoxChanged(const double value)
{
SandboxEditor::SetAngleSnappingSize(static_cast<float>(value));
SandboxEditor::SetAngleSnappingSize(aznumeric_cast<float>(value));
}
void CViewportTitleDlg::UpdateOverFlowMenuState()
{
bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked();
const bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked();
{
QSignalBlocker signalBlocker(m_enableGridSnappingAction);
m_enableGridSnappingAction->setChecked(gridSnappingActive);
}
m_gridSizeActionWidget->setEnabled(gridSnappingActive);
bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked();
const bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked();
{
QSignalBlocker signalBlocker(m_enableAngleSnappingAction);
m_enableAngleSnappingAction->setChecked(angleSnappingActive);
}
m_angleSizeActionWidget->setEnabled(angleSnappingActive);
{
QSignalBlocker signalBlocker(m_enableGridVisualizationAction);
m_enableGridVisualizationAction->setChecked(SandboxEditor::ShowingGrid());
}
}
namespace
+2 -1
View File
@@ -171,6 +171,7 @@ protected:
QAction* m_enableVRAction = nullptr;
QAction* m_enableGridSnappingAction = nullptr;
QAction* m_enableAngleSnappingAction = nullptr;
QAction* m_enableGridVisualizationAction = nullptr;
QComboBox* m_cameraSpeed = nullptr;
AzQtComponents::DoubleSpinBox* m_gridSpinBox = nullptr;
AzQtComponents::DoubleSpinBox* m_angleSpinBox = nullptr;
@@ -184,7 +185,7 @@ protected:
namespace AzToolsFramework
{
//! A component to reflect scriptable commands for the Editor
//! A component to reflect scriptable commands for the Editor.
class ViewportTitleDlgPythonFuncsHandler
: public AZ::Component
{
@@ -3408,7 +3408,14 @@ LUA_API const Node* lua_getDummyNode()
const BehaviorParameter* arg = method->GetArgument(iArg);
BehaviorClass* argClass = nullptr;
LuaLoadFromStack fromStack = FromLuaStack(context, arg, argClass);
AZ_Assert(fromStack, "Argument %s for Method %s doesn't have support to be converted to Lua!", arg->m_name, method->m_name.c_str());
AZ_Assert(fromStack,
"The argument type: %s for method: %s is not serialized and/or reflected for scripting.\n"
"Make sure %s is added to the SerializeContext and reflected to the BehaviorContext\n"
"For example, verify these two exist and are being called in a Reflect function:\n"
"serializeContext->Class<%s>();\n"
"behaviorContext->Class<%s>();\n"
"%s will not be available for scripting unless these requirements are met."
, arg->m_name, method->m_name.c_str(), arg->m_name, arg->m_name, arg->m_name, method->m_name.c_str());
m_fromLua.push_back(AZStd::make_pair(fromStack, argClass));
}
@@ -5066,13 +5073,26 @@ LUA_API const Node* lua_getDummyNode()
// Check all constructors if they have use ScriptDataContext and if so choose this one
if (!customConstructorMethod)
{
int overrideIndex = -1;
AZ::AttributeReader(nullptr, FindAttribute
( Script::Attributes::DefaultConstructorOverrideIndex, behaviorClass->m_attributes)).Read<int>(overrideIndex);
int methodIndex = 0;
for (BehaviorMethod* method : behaviorClass->m_constructors)
{
if (methodIndex == overrideIndex)
{
customConstructorMethod = method;
break;
}
if (method->GetNumArguments() && method->GetArgument(method->GetNumArguments() - 1)->m_typeId == AZ::AzTypeInfo<ScriptDataContext>::Uuid())
{
customConstructorMethod = method;
break;
}
++methodIndex;
}
}
@@ -21,6 +21,7 @@ namespace AZ
static constexpr AZ::Crc32 ClassNameOverride = AZ_CRC_CE("ScriptClassNameOverride"); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name
static constexpr AZ::Crc32 MethodOverride = AZ_CRC_CE("ScriptFunctionOverride"); ///< Use a custom function in the attribute instead of the function
static constexpr AZ::Crc32 ConstructorOverride = AZ_CRC_CE("ConstructorOverride"); ///< You can provide a custom constructor to be called when created from Lua script
static constexpr AZ::Crc32 DefaultConstructorOverrideIndex = AZ_CRC_CE("DefaultConstructorOverrideIndex"); ///< Use a different class constructor as the default constructor in Lua
static constexpr AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals
static constexpr AZ::Crc32 GenericConstructorOverride = AZ_CRC_CE("GenericConstructorOverride"); ///< You can provide a custom constructor to be called when creating a script
static constexpr AZ::Crc32 ReaderWriterOverride = AZ_CRC_CE("ReaderWriterOverride"); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM
@@ -133,6 +133,8 @@ namespace AZ
const static AZ::Crc32 AllowClearAsset = AZ_CRC("AllowClearAsset", 0x24827182);
// Show the name of the asset that was produced from the source asset
const static AZ::Crc32 ShowProductAssetFileName = AZ_CRC("ShowProductAssetFileName");
//! Regular expression pattern filter for source files
const static AZ::Crc32 SourceAssetFilterPattern = AZ_CRC_CE("SourceAssetFilterPattern");
//! Component icon attributes
const static AZ::Crc32 Icon = AZ_CRC("Icon", 0x659429db);
@@ -204,6 +204,22 @@ namespace AZ
// BaseJsonSerializer
//
JsonSerializationResult::Result BaseJsonSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
JsonDeserializerContext& context)
{
JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::ReadField);
result.Combine(ContinueLoading(outputValue, outputValueTypeId, inputValue, context, ContinuationFlags::IgnoreTypeSerializer));
return context.Report(result, "Ignoring custom serialization during load");
}
JsonSerializationResult::Result BaseJsonSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context)
{
JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::WriteValue);
result.Combine(ContinueStoring(outputValue, inputValue, defaultValue, valueTypeId, context, ContinuationFlags::IgnoreTypeSerializer));
return context.Report(result, "Ignoring custom serialization during store");
}
BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const
{
return OperationFlags::None;
@@ -180,13 +180,16 @@ namespace AZ
//! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported.
//! The serializer is responsible for casting to the proper type and safely writing to the outputValue memory.
//! \note The default implementation is to load the object ignoring a custom serializers for the type, which allows for custom serializers
//! to modify the object after all default loading has occurred.
virtual JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
JsonDeserializerContext& context) = 0;
JsonDeserializerContext& context);
//! Write the input value to a rapidjson value if the default value is not null and doesn't match the input value, otherwise
//! an error is returned and sets the rapidjson value to a null value.
//! \note The default implementation is to store the object ignoring custom serializers.
virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context) = 0;
const Uuid& valueTypeId, JsonSerializerContext& context);
//! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used.
virtual OperationFlags GetOperationsFlags() const;
@@ -150,7 +150,7 @@ namespace AZ
{
// Not using InsertTypeId here to avoid needing to create the temporary value and swap it in that call.
node.AddMember(rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier),
StoreTypeName(classData, context), context.GetJsonAllocator());
StoreTypeName(classData, classData.m_typeId, context), context.GetJsonAllocator());
result = ResultCode(Tasks::WriteValue, Outcomes::Success);
}
return result.Combine(StoreClass(node, object, defaultObject, classData, context));
@@ -531,7 +531,7 @@ namespace AZ
return ResolvePointerResult::ContinueProcessing;
}
rapidjson::Value JsonSerializer::StoreTypeName(const SerializeContext::ClassData& classData, JsonSerializerContext& context)
rapidjson::Value JsonSerializer::StoreTypeName(const SerializeContext::ClassData& classData, const Uuid& typeId, JsonSerializerContext& context)
{
rapidjson::Value result;
AZStd::vector<Uuid> ids = context.GetSerializeContext()->FindClassId(Crc32(classData.m_name));
@@ -544,7 +544,7 @@ namespace AZ
// Only write the Uuid for the class if there are multiple classes sharing the same name.
// In this case it wouldn't be enough to determine which class needs to be used. The
// class name is still added as a comment for be friendlier for users to read.
AZStd::string fullName = classData.m_typeId.ToString<AZStd::string>();
AZStd::string fullName = typeId.ToString<AZStd::string>();
fullName += ' ';
fullName += classData.m_name;
result.SetString(fullName.c_str(), aznumeric_caster(fullName.size()), context.GetJsonAllocator());
@@ -560,7 +560,7 @@ namespace AZ
const SerializeContext::ClassData* data = context.GetSerializeContext()->FindClassData(typeId);
if (data)
{
output = JsonSerializer::StoreTypeName(*data, context);
output = JsonSerializer::StoreTypeName(*data, typeId, context);
return context.Report(Tasks::WriteValue, Outcomes::Success, "Type id successfully stored to json value.");
}
else
@@ -580,7 +580,7 @@ namespace AZ
{
rapidjson::Value insertedObject(rapidjson::kObjectType);
insertedObject.AddMember(
rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier), StoreTypeName(classData, context),
rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier), StoreTypeName(classData, classData.m_typeId, context),
context.GetJsonAllocator());
for (auto& element : output.GetObject())
@@ -79,7 +79,7 @@ namespace AZ
const void*& object, const void*& defaultObject, AZStd::any& defaultObjectStorage,
const SerializeContext::ClassData*& elementClassData, const AZ::IRttiHelper& rtti, JsonSerializerContext& context);
static rapidjson::Value StoreTypeName(const SerializeContext::ClassData& classData, JsonSerializerContext& context);
static rapidjson::Value StoreTypeName(const SerializeContext::ClassData& classData, const Uuid& typeId, JsonSerializerContext& context);
static JsonSerializationResult::ResultCode StoreTypeName(rapidjson::Value& output,
const Uuid& typeId, JsonSerializerContext& context);
+2 -3
View File
@@ -165,13 +165,12 @@ namespace AZ::Utils
}
Container fileContent;
fileContent.resize(length);
fileContent.resize_no_construct(length);
AZ::IO::SizeType bytesRead = file.Read(length, fileContent.data());
file.Close();
// Resize again just in case bytesRead is less than length for some reason
fileContent.resize(bytesRead);
fileContent.resize_no_construct(bytesRead);
return AZ::Success(AZStd::move(fileContent));
}
@@ -10,6 +10,72 @@
#include <Tests/Serialization/Json/JsonSerializationTests.h>
#include <Tests/Serialization/Json/TestCases_Classes.h>
#include <Tests/Serialization/Json/TestCases_Pointers.h>
#include <AzCore/Asset/AssetCommon.h>
namespace AZ
{
template<typename T>
struct SerializeGenericTypeInfo<JsonSerializationTests::TemplatedClass<T>>
{
using ThisType = JsonSerializationTests::TemplatedClass<T>;
class GenericTemplatedClassInfo : public GenericClassInfo
{
public:
GenericTemplatedClassInfo()
: m_classData{ SerializeContext::ClassData::Create<ThisType>(
"TemplatedClass", "{CA4ADF74-66E7-4D16-B4AC-F71278C60EC7}", nullptr, nullptr) }
{
}
SerializeContext::ClassData* GetClassData() override
{
return &m_classData;
}
size_t GetNumTemplatedArguments() override
{
return 1;
}
const Uuid& GetSpecializedTypeId() const override
{
return m_classData.m_typeId;
}
const Uuid& GetGenericTypeId() const override
{
return m_classData.m_typeId;
}
const Uuid& GetTemplatedTypeId(size_t element) override
{
(void)element;
return SerializeGenericTypeInfo<T>::GetClassTypeId();
}
void Reflect(SerializeContext* serializeContext) override
{
if (serializeContext)
{
serializeContext->RegisterGenericClassInfo(
GetSpecializedTypeId(), this, &AZ::AnyTypeInfoConcept<Data::Asset<Data::AssetData>>::CreateAny);
serializeContext->RegisterGenericClassInfo(
azrtti_typeid<ThisType>(), this,
&AZ::AnyTypeInfoConcept<ThisType>::CreateAny);
}
}
SerializeContext::ClassData m_classData;
};
using ClassInfoType = GenericTemplatedClassInfo;
static ClassInfoType* GetGenericInfo()
{
return GetCurrentSerializeContextModule().CreateGenericClassInfo<ThisType>();
}
};
} // namespace AZ
namespace JsonSerializationTests
{
@@ -286,4 +352,32 @@ namespace JsonSerializationTests
EXPECT_EQ(Processing::Halted, result.GetProcessing());
EXPECT_EQ(Outcomes::Unknown, result.GetOutcome());
}
TEST_F(JsonSerializationTests, StoreTypeId_TemplatedType_StoresUuidWithName)
{
using namespace AZ;
using namespace AZ::JsonSerializationResult;
m_serializeContext->RegisterGenericType<TemplatedClass<A::Inherited>>();
m_serializeContext->RegisterGenericType<TemplatedClass<BaseClass>>();
Uuid input = azrtti_typeid<TemplatedClass<A::Inherited>>();
ResultCode result = JsonSerialization::StoreTypeId(
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
AZStd::string expected =
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<A::Inherited>>().ToString<AZStd::string>().c_str());
Expect_DocStrEq(expected.c_str(), false);
input = azrtti_typeid<TemplatedClass<BaseClass>>();
result = JsonSerialization::StoreTypeId(
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
expected =
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<BaseClass>>().ToString<AZStd::string>().c_str());
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq(expected.c_str(), false);
}
} // namespace JsonSerializationTests
@@ -9,9 +9,27 @@
#include <AzToolsFramework/Application/EditorEntityManager.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
namespace AzToolsFramework
{
static bool AreEntitiesValidForDuplication(const EntityIdList& entityIds)
{
for (AZ::EntityId entityId : entityIds)
{
if (GetEntityById(entityId) == nullptr)
{
AZ_Error(
"Entity", false,
"Entity with id '%llu' is not found. This can happen when you try to duplicate the entity before it is created. Please "
"ensure entities are created before trying to duplicate them.",
static_cast<AZ::u64>(entityId));
return false;
}
}
return true;
}
void EditorEntityManager::Start()
{
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
@@ -62,7 +80,11 @@ namespace AzToolsFramework
EntityIdList selectedEntities;
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
if (AreEntitiesValidForDuplication(selectedEntities))
{
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
}
}
void EditorEntityManager::DuplicateEntityById(AZ::EntityId entityId)
@@ -72,7 +94,10 @@ namespace AzToolsFramework
void EditorEntityManager::DuplicateEntities(const EntityIdList& entities)
{
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
if (AreEntitiesValidForDuplication(entities))
{
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
}
}
}
@@ -34,5 +34,4 @@ namespace AzToolsFramework
private:
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
};
}
@@ -99,6 +99,18 @@ namespace AzToolsFramework
}
}
if (selection.GetSelectedAssetIds().empty())
{
for (auto& filePath : selection.GetSelectedFilePaths())
{
if (!filePath.empty())
{
selectedAsset = true;
m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(filePath);
}
}
}
if (!selectedAsset)
{
m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory());
@@ -10,18 +10,24 @@
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
#if !defined(Q_MOC_RUN)
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
#include <QRegExp>
AZ_POP_DISABLE_WARNING
#endif
namespace AzToolsFramework
{
namespace AssetBrowser
{
namespace
{
FilterConstType ProductsNoFoldersFilter()
FilterConstType EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType entryType = AssetBrowserEntry::AssetEntryType::Product)
{
EntryTypeFilter* productFilter = new EntryTypeFilter();
productFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product);
EntryTypeFilter* entryTypeFilter = new EntryTypeFilter();
entryTypeFilter->SetEntryType(entryType);
// in case entry is a source or folder, it may still contain relevant product
productFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
entryTypeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
EntryTypeFilter* foldersFilter = new EntryTypeFilter();
foldersFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Folder);
@@ -30,7 +36,7 @@ namespace AzToolsFramework
noFoldersFilter->SetFilter(FilterConstType(foldersFilter));
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
compFilter->AddFilter(FilterConstType(productFilter));
compFilter->AddFilter(FilterConstType(entryTypeFilter));
compFilter->AddFilter(FilterConstType(noFoldersFilter));
return FilterConstType(compFilter);
@@ -79,15 +85,39 @@ namespace AzToolsFramework
void AssetSelectionModel::SetSelectedAssetIds(const AZStd::vector<AZ::Data::AssetId>& selectedAssetIds)
{
m_selectedFilePaths.clear();
m_selectedAssetIds = selectedAssetIds;
}
void AssetSelectionModel::SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId)
{
m_selectedFilePaths.clear();
m_selectedAssetIds.clear();
m_selectedAssetIds.push_back(selectedAssetId);
}
const AZStd::vector<AZStd::string>& AssetSelectionModel::GetSelectedFilePaths() const
{
return m_selectedFilePaths;
}
void AssetSelectionModel::SetSelectedFilePaths(const AZStd::vector<AZStd::string>& selectedFilePaths)
{
m_selectedAssetIds.clear();
m_selectedFilePaths = selectedFilePaths;
}
void AssetSelectionModel::SetSelectedFilePath(const AZStd::string& selectedFilePath)
{
m_selectedAssetIds.clear();
m_selectedFilePaths.clear();
m_selectedFilePaths.push_back(selectedFilePath);
}
void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory)
{
m_defaultDirectory = defaultDirectory;
@@ -136,7 +166,7 @@ namespace AzToolsFramework
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
compFilter->AddFilter(assetTypeFilterPtr);
compFilter->AddFilter(ProductsNoFoldersFilter());
compFilter->AddFilter(EntryTypeNoFoldersFilter());
selection.SetSelectionFilter(FilterConstType(compFilter));
selection.SetMultiselect(multiselect);
@@ -169,7 +199,7 @@ namespace AzToolsFramework
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
compFilter->AddFilter(anyAssetTypeFilterPtr);
compFilter->AddFilter(ProductsNoFoldersFilter());
compFilter->AddFilter(EntryTypeNoFoldersFilter());
selection.SetSelectionFilter(FilterConstType(compFilter));
selection.SetMultiselect(multiselect);
@@ -190,7 +220,28 @@ namespace AzToolsFramework
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
compFilter->AddFilter(assetGroupFilterPtr);
compFilter->AddFilter(ProductsNoFoldersFilter());
compFilter->AddFilter(EntryTypeNoFoldersFilter());
selection.SetSelectionFilter(FilterConstType(compFilter));
selection.SetMultiselect(multiselect);
return selection;
}
AssetSelectionModel AssetSelectionModel::SourceAssetTypeSelection(const QString& pattern, bool multiselect)
{
AssetSelectionModel selection;
RegExpFilter* patternFilter = new RegExpFilter();
patternFilter->SetFilterPattern(pattern);
patternFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
auto patternFilterPtr = FilterConstType(patternFilter);
selection.SetDisplayFilter(patternFilterPtr);
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
compFilter->AddFilter(patternFilterPtr);
compFilter->AddFilter(EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType::Source));
selection.SetSelectionFilter(FilterConstType(compFilter));
selection.SetMultiselect(multiselect);
@@ -204,7 +255,7 @@ namespace AzToolsFramework
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::OR);
selection.SetDisplayFilter(FilterConstType(compFilter));
selection.SetSelectionFilter(ProductsNoFoldersFilter());
selection.SetSelectionFilter(EntryTypeNoFoldersFilter());
selection.SetMultiselect(multiselect);
return selection;
@@ -44,6 +44,10 @@ namespace AzToolsFramework
void SetSelectedAssetIds(const AZStd::vector<AZ::Data::AssetId>& selectedAssetIds);
void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId);
const AZStd::vector<AZStd::string>& GetSelectedFilePaths() const;
void SetSelectedFilePaths(const AZStd::vector<AZStd::string>& selectedFilePaths);
void SetSelectedFilePath(const AZStd::string& selectedFilePath);
void SetDefaultDirectory(AZStd::string_view defaultDirectory);
AZStd::string_view GetDefaultDirectory() const;
@@ -60,6 +64,7 @@ namespace AzToolsFramework
static AssetSelectionModel AssetTypeSelection(const char* assetTypeName, bool multiselect = false);
static AssetSelectionModel AssetTypesSelection(const AZStd::vector<AZ::Data::AssetType>& assetTypes, bool multiselect = false);
static AssetSelectionModel AssetGroupSelection(const char* group, bool multiselect = false);
static AssetSelectionModel SourceAssetTypeSelection(const QString& pattern, bool multiselect = false);
static AssetSelectionModel EverythingSelection(bool multiselect = false);
private:
@@ -68,8 +73,12 @@ namespace AzToolsFramework
// some entries like folder should always be displayed, but not always selectable, thus 2 separate filters
FilterConstType m_selectionFilter;
FilterConstType m_displayFilter;
//! Selection can be based on asset ids (for products), or file paths (for sources)
//! These are mututally exclusive
AZStd::vector<AZ::Data::AssetId> m_selectedAssetIds;
AZStd::vector<AZStd::string> m_selectedFilePaths;
AZStd::vector<const AssetBrowserEntry*> m_results;
AZStd::string m_defaultDirectory;
@@ -251,6 +251,40 @@ namespace AzToolsFramework
return false;
}
//////////////////////////////////////////////////////////////////////////
// RegExpFilter
//////////////////////////////////////////////////////////////////////////
RegExpFilter::RegExpFilter()
: m_filterPattern("")
{
}
void RegExpFilter::SetFilterPattern(const QString& filterPattern)
{
m_filterPattern = filterPattern;
Q_EMIT updatedSignal();
}
QString RegExpFilter::GetNameInternal() const
{
return m_filterPattern;
}
bool RegExpFilter::MatchInternal(const AssetBrowserEntry* entry) const
{
// no filter pattern matches any asset
if (m_filterPattern.isEmpty())
{
return true;
}
// entry's name matches regular expression pattern
QRegExp regExp(m_filterPattern);
regExp.setPatternSyntax(QRegExp::Wildcard);
return regExp.exactMatch(entry->GetDisplayName());
}
//////////////////////////////////////////////////////////////////////////
// AssetTypeFilter
//////////////////////////////////////////////////////////////////////////
@@ -115,6 +115,28 @@ namespace AzToolsFramework
QString m_filterString;
};
//////////////////////////////////////////////////////////////////////////
// RegExpFilter
//////////////////////////////////////////////////////////////////////////
//! RegExpFilter filters assets based on a regular expression pattern
class RegExpFilter
: public AssetBrowserEntryFilter
{
Q_OBJECT
public:
RegExpFilter();
~RegExpFilter() override = default;
void SetFilterPattern(const QString& filterPattern);
protected:
QString GetNameInternal() const override;
bool MatchInternal(const AssetBrowserEntry* entry) const override;
private:
QString m_filterPattern;
};
//////////////////////////////////////////////////////////////////////////
// AssetTypeFilter
//////////////////////////////////////////////////////////////////////////
@@ -1158,7 +1158,8 @@ namespace AzToolsFramework
// Select the duplicated entities/instances
auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances");
selectionUndo->SetParent(undoBatch.GetUndoBatch());
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
ToolsApplicationRequestBus::Broadcast(
&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
}
return AZ::Success(AZStd::move(duplicatedEntityAndInstanceIds));
@@ -860,18 +860,20 @@ namespace AzToolsFramework
return;
}
bool isDuringUndoRedo = false;
EBUS_EVENT_RESULT(isDuringUndoRedo, AzToolsFramework::ToolsApplicationRequests::Bus, IsDuringUndoRedo);
if (!isDuringUndoRedo)
bool suppressTransformChangedEvent = m_suppressTransformChangedEvent;
// temporarily disable calling OnTransformChanged, because CheckApplyCachedWorldTransform is not guaranteed
// to call it when m_cachedWorldTransform is identity. We send it manually later.
m_suppressTransformChangedEvent = false;
// When parent comes online, compute local TM from world TM.
CheckApplyCachedWorldTransform(parentTransform->GetWorldTM());
if (!m_initialized)
{
// When parent comes online, compute local TM from world TM.
CheckApplyCachedWorldTransform(parentTransform->GetWorldTM());
}
else
{
// During undo operations, just apply our local TM.
m_initialized = true;
// If this is the first time this entity is being activated, manually compute OnTransformChanged
// this can occur when either the entity first created or undo/redo command is performed
OnTransformChanged(AZ::Transform::Identity(), parentTransform->GetWorldTM());
}
m_suppressTransformChangedEvent = suppressTransformChangedEvent;
auto& parentChildIds = GetParentTransformComponent()->m_childrenEntityIds;
if (parentChildIds.end() == AZStd::find(parentChildIds.begin(), parentChildIds.end(), GetEntityId()))
@@ -242,6 +242,9 @@ namespace AzToolsFramework
// element is used rather than a data element.
bool m_addNonUniformScaleButton = false;
// Used to check whether entity was just created vs manually reactivated. Set true after OnEntityActivated is called the first time.
bool m_initialized = false;
// Deprecated
AZ::InterpolationMode m_interpolatePosition;
AZ::InterpolationMode m_interpolateRotation;
@@ -39,7 +39,12 @@ namespace AzToolsFramework
typeFilter->SetAssetType(filterType);
typeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
m_assetBrowserFilterModel->SetFilter(FilterConstType(typeFilter));
SetFilter(FilterConstType(typeFilter));
}
void AssetCompleterModel::SetFilter(FilterConstType filter)
{
m_assetBrowserFilterModel->SetFilter(filter);
RefreshAssetList();
}
@@ -120,9 +125,6 @@ namespace AzToolsFramework
int rows = m_assetBrowserFilterModel->rowCount(index);
if (rows == 0)
{
if (index != QModelIndex()) {
AZ_Error("AssetCompleterModel", false, "No children detected in FetchResources()");
}
return;
}
@@ -131,7 +133,7 @@ namespace AzToolsFramework
QModelIndex childIndex = m_assetBrowserFilterModel->index(i, 0, index);
AssetBrowserEntry* childEntry = GetAssetEntry(m_assetBrowserFilterModel->mapToSource(childIndex));
if (childEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product)
if (childEntry->GetEntryType() == m_entryType)
{
ProductAssetBrowserEntry* productEntry = static_cast<ProductAssetBrowserEntry*>(childEntry);
AZStd::string assetName;
@@ -167,7 +169,6 @@ namespace AzToolsFramework
return m_assets[index.row()].m_displayName;
}
const AZ::Data::AssetId AssetCompleterModel::GetAssetIdFromIndex(const QModelIndex& index)
{
if (!index.isValid())
@@ -177,4 +178,19 @@ namespace AzToolsFramework
return m_assets[index.row()].m_assetId;
}
const AZStd::string_view AssetCompleterModel::GetPathFromIndex(const QModelIndex& index)
{
if (!index.isValid())
{
return "";
}
return m_assets[index.row()].m_path;
}
void AssetCompleterModel::SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType)
{
m_entryType = entryType;
}
}
@@ -32,6 +32,7 @@ namespace AzToolsFramework
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void SetFilter(AZ::Data::AssetType filterType);
void SetFilter(FilterConstType filter);
void RefreshAssetList();
void SearchStringHighlight(QString searchString);
@@ -39,6 +40,9 @@ namespace AzToolsFramework
const AZStd::string_view GetNameFromIndex(const QModelIndex& index);
const AZ::Data::AssetId GetAssetIdFromIndex(const QModelIndex& index);
const AZStd::string_view GetPathFromIndex(const QModelIndex& index);
void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType);
private:
struct AssetItem
@@ -57,6 +61,8 @@ namespace AzToolsFramework
AZStd::vector<AssetItem> m_assets;
//! String that will be highlighted in the suggestions
QString m_highlightString;
AssetBrowserEntry::AssetEntryType m_entryType = AssetBrowserEntry::AssetEntryType::Product;
};
}
@@ -1288,7 +1288,7 @@ namespace AzToolsFramework
return newCtrl;
}
void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
void AssetPropertyHandlerDefault::ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
{
(void)debugName;
@@ -1487,6 +1487,11 @@ namespace AzToolsFramework
}
}
void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
{
ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
}
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
{
(void)index;
@@ -1629,8 +1634,8 @@ namespace AzToolsFramework
void RegisterAssetPropertyHandler()
{
EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AssetPropertyHandlerDefault());
EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault());
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew AssetPropertyHandlerDefault());
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault());
}
}
@@ -175,10 +175,11 @@ namespace AzToolsFramework
virtual void SetFolderSelection(const AZStd::string& /* folderPath */) {}
virtual void ClearAssetInternal();
void ConfigureAutocompleter();
virtual void ConfigureAutocompleter();
void RefreshAutocompleter();
void EnableAutocompleter();
void DisableAutocompleter();
const QModelIndex GetSourceIndex(const QModelIndex& index);
void HandleFieldClear();
AZStd::string AddDefaultSuffix(const AZStd::string& filename);
@@ -235,20 +236,19 @@ namespace AzToolsFramework
void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType);
void SetCurrentAssetHint(const AZStd::string& hint);
void SetDefaultAssetID(const AZ::Data::AssetId& defaultID);
void PopupAssetPicker();
virtual void PopupAssetPicker();
void OnClearButtonClicked();
void UpdateAssetDisplay();
void OnLineEditFocus(bool focus);
virtual void OnEditButtonClicked();
void OnThumbnailClicked();
void OnCompletionModelReset();
void OnAutocomplete(const QModelIndex& index);
virtual void OnAutocomplete(const QModelIndex& index);
void OnTextChange(const QString& text);
void OnReturnPressed();
void ShowContextMenu(const QPoint& pos);
private:
const QModelIndex GetSourceIndex(const QModelIndex& index);
void UpdateThumbnail();
};
@@ -270,7 +270,8 @@ namespace AzToolsFramework
virtual void UpdateWidgetInternalTabbing(PropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); }
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName);
void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override;
};
@@ -3534,10 +3534,9 @@ namespace AzToolsFramework
debugDisplay.SetLineWidth(1.0f);
const float labelOffset = ed_viewportGizmoAxisLabelOffset;
const float screenScale = GetScreenDisplayScaling(viewportId);
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize;
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize;
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize;
// draw the label of of each axis for the gizmo
const float labelSize = ed_viewportGizmoAxisLabelSize;
@@ -11,6 +11,8 @@
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <Prefab/PrefabTestComponent.h>
#include <Prefab/PrefabTestDomUtils.h>
@@ -50,6 +52,15 @@ namespace UnitTest
GetApplication()->RegisterComponentDescriptor(PrefabTestComponent::CreateDescriptor());
GetApplication()->RegisterComponentDescriptor(PrefabTestComponentWithUnReflectedTypeMember::CreateDescriptor());
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack);
AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application");
}
void PrefabTestFixture::TearDownEditorFixtureImpl()
{
m_undoStack = nullptr;
}
AZStd::unique_ptr<ToolsTestApplication> PrefabTestFixture::CreateTestApplication()
@@ -57,7 +68,20 @@ namespace UnitTest
return AZStd::make_unique<PrefabTestToolsApplication>("PrefabTestApplication");
}
AZ::Entity* PrefabTestFixture::CreateEntity(const char* entityName, const bool shouldActivate)
void PrefabTestFixture::CreateRootPrefab()
{
auto entityOwnershipService = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
ASSERT_TRUE(entityOwnershipService != nullptr);
entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", "");
auto rootEntityReference = entityOwnershipService->GetRootPrefabInstance()->get().GetContainerEntity();
ASSERT_TRUE(rootEntityReference.has_value());
auto& rootEntity = rootEntityReference->get();
rootEntity.Deactivate();
rootEntity.CreateComponent<AzToolsFramework::Components::TransformComponent>();
rootEntity.Activate();
}
AZ::Entity* PrefabTestFixture::CreateEntity(AZStd::string entityName, const bool shouldActivate)
{
// Circumvent the EntityContext system and generate a new entity with a transformcomponent
AZ::Entity* newEntity = aznew AZ::Entity(entityName);
@@ -71,8 +95,43 @@ namespace UnitTest
return newEntity;
}
AZ::EntityId PrefabTestFixture::CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId)
{
auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3());
AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str());
AZ::EntityId entityId = createResult.GetValue();
AZ::Entity* entity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
entity->Deactivate();
entity->SetName(name);
// Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test
// environment entities aren't created with a default transform component, so CreateEntity won't correctly parent.
// We get the actual target parent ID here, then create our missing transform component.
if (!parentId.IsValid())
{
auto prefabEditorEntityOwnershipInterface = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId();
}
auto transform = aznew AzToolsFramework::Components::TransformComponent;
transform->SetParent(parentId);
entity->AddComponent(transform);
entity->Activate();
// Update our undo cache entry to include the rename / reparent as one atomic operation.
m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop());
m_prefabSystemComponent->OnSystemTick();
return entityId;
}
void PrefabTestFixture::CompareInstances(const AzToolsFramework::Prefab::Instance& instanceA,
const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities)
const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities)
{
AzToolsFramework::Prefab::TemplateId templateAId = instanceA.GetTemplateId();
AzToolsFramework::Prefab::TemplateId templateBId = instanceB.GetTemplateId();
@@ -125,4 +184,22 @@ namespace UnitTest
EXPECT_EQ(entityInInstance->GetState(), AZ::Entity::State::Active);
}
}
void PrefabTestFixture::ProcessDeferredUpdates()
{
// Force a prefab propagation for updates that are deferred to the next tick.
m_prefabSystemComponent->OnSystemTick();
}
void PrefabTestFixture::Undo()
{
m_undoStack->Undo();
ProcessDeferredUpdates();
}
void PrefabTestFixture::Redo()
{
m_undoStack->Redo();
ProcessDeferredUpdates();
}
}
@@ -49,10 +49,13 @@ namespace UnitTest
inline static const char* CarPrefabMockFilePath = "SomePathToCar";
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
AZStd::unique_ptr<ToolsTestApplication> CreateTestApplication() override;
AZ::Entity* CreateEntity(const char* entityName, const bool shouldActivate = true);
void CreateRootPrefab();
AZ::Entity* CreateEntity(AZStd::string entityName, const bool shouldActivate = true);
AZ::EntityId CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId = AZ::EntityId());
void CompareInstances(const Instance& instanceA, const Instance& instanceB, bool shouldCompareLinkIds = true,
bool shouldCompareContainerEntities = true);
@@ -62,10 +65,20 @@ namespace UnitTest
//! Validates that all entities within a prefab instance are in 'Active' state.
void ValidateInstanceEntitiesActive(Instance& instance);
// Kicks off any updates scheduled for the next tick
virtual void ProcessDeferredUpdates();
// Performs an undo operation and ensures the tick-scheduled updates happen
void Undo();
// Performs a redo operation and ensures the tick-scheduled updates happen
void Redo();
PrefabSystemComponent* m_prefabSystemComponent = nullptr;
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
InstanceUpdateExecutorInterface* m_instanceUpdateExecutorInterface = nullptr;
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr;
};
}
@@ -18,7 +18,10 @@
#include <AzFramework/Components/TransformComponent.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <Prefab/PrefabTestFixture.h>
#include <AZTestShared/Math/MathTestHelpers.h>
@@ -1063,4 +1066,67 @@ R"DELIMITER(<ObjectStream version="1">
}
}
}
// Fixture provides a root prefab with Transform component and listens for TransformNotificationBus.
class TransformComponentActivationTest
: public PrefabTestFixture
, public TransformNotificationBus::Handler
{
protected:
void SetUpEditorFixtureImpl() override
{
PrefabTestFixture::SetUpEditorFixtureImpl();
CreateRootPrefab();
}
void TearDownEditorFixtureImpl() override
{
BusDisconnect();
PrefabTestFixture::TearDownEditorFixtureImpl();
}
void OnTransformChanged(const Transform& /*local*/, const Transform& /*world*/) override
{
m_transformUpdated = true;
}
void MoveEntity(AZ::EntityId entityId)
{
AzToolsFramework::ScopedUndoBatch undoBatch("Move Entity");
TransformBus::Event(entityId, &TransformInterface::SetWorldTranslation, Vector3(1.f, 0.f, 0.f));
}
bool m_transformUpdated = false;
};
TEST_F(TransformComponentActivationTest, TransformChangedEventIsSentWhenEntityIsActivatedViaUndoRedo)
{
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
MoveEntity(entityId);
BusConnect(entityId);
// verify that undoing/redoing move operations fires TransformChanged event
Undo();
EXPECT_TRUE(m_transformUpdated);
m_transformUpdated = false;
Redo();
EXPECT_TRUE(m_transformUpdated);
m_transformUpdated = false;
}
TEST_F(TransformComponentActivationTest, TransformChangedEventIsNotSentWhenEntityIsDeactivatedAndActivated)
{
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
BusConnect(entityId);
// verify that simply activating/deactivating an entity does not fire TransformChanged event
Entity* entity = nullptr;
ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
entity->Deactivate();
entity->Activate();
EXPECT_FALSE(m_transformUpdated);
}
} // namespace UnitTest
@@ -37,16 +37,11 @@ namespace UnitTest
m_model->Initialize();
m_modelTester =
AZStd::make_unique<QAbstractItemModelTester>(m_model.get(), QAbstractItemModelTester::FailureReportingMode::Fatal);
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack);
AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application");
// Create a new root prefab - the synthetic "NewLevel.prefab" that comes in by default isn't suitable for outliner tests
// because it's created before the EditorEntityModel that our EntityOutlinerListModel subscribes to, and we want to
// recreate it as part of the fixture regardless.
auto entityOwnershipService = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", "");
CreateRootPrefab();
}
void TearDownEditorFixtureImpl() override
@@ -56,45 +51,7 @@ namespace UnitTest
m_model.reset();
PrefabTestFixture::TearDownEditorFixtureImpl();
}
// Creates an entity with a given name as one undoable operation
// Parents to parentId, or the root prefab container entity if parentId is invalid
AZ::EntityId CreateNamedEntity(AZStd::string name, AZ::EntityId parentId = AZ::EntityId())
{
auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3());
AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str());
AZ::EntityId entityId = createResult.GetValue();
AZ::Entity* entity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
entity->Deactivate();
entity->SetName(name);
// Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test
// environment entities aren't created with a default transform component, so CreateEntity won't correctly parent.
// We get the actual target parent ID here, then create our missing transform component.
if (!parentId.IsValid())
{
auto prefabEditorEntityOwnershipInterface = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId();
}
auto transform = aznew AzToolsFramework::Components::TransformComponent;
transform->SetParent(parentId);
entity->AddComponent(transform);
entity->Activate();
// Update our undo cache entry to include the rename / reparent as one atomic operation.
m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop());
ProcessDeferredUpdates();
return entityId;
}
// Helper to visualize debug state
void PrintModel()
{
@@ -125,32 +82,16 @@ namespace UnitTest
}
// Kicks off any updates scheduled for the next tick
void ProcessDeferredUpdates()
void ProcessDeferredUpdates() override
{
// Force a prefab propagation for updates that are deferred to the next tick.
m_prefabSystemComponent->OnSystemTick();
PrefabTestFixture::ProcessDeferredUpdates();
// Ensure the model process its entity update queue
m_model->ProcessEntityUpdates();
}
// Performs an undo operation and ensures the tick-scheduled updates happen
void Undo()
{
m_undoStack->Undo();
ProcessDeferredUpdates();
}
// Performs a redo operation and ensures the tick-scheduled updates happen
void Redo()
{
m_undoStack->Redo();
ProcessDeferredUpdates();
}
AZStd::unique_ptr<AzToolsFramework::EntityOutlinerListModel> m_model;
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTester;
AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr;
};
TEST_F(EntityOutlinerTest, TestCreateFlatHierarchyUndoAndRedoWorks)
@@ -159,7 +100,7 @@ namespace UnitTest
for (size_t i = 0; i < entityCount; ++i)
{
CreateNamedEntity(AZStd::string::format("Entity%zu", i));
CreateEntityUnderRootPrefab(AZStd::string::format("Entity%zu", i));
EXPECT_EQ(m_model->rowCount(GetRootIndex()), i + 1);
}
@@ -195,7 +136,7 @@ namespace UnitTest
AZ::EntityId parentId;
for (int i = 0; i < depth; i++)
{
parentId = CreateNamedEntity(AZStd::string::format("EntityDepth%i", i), parentId);
parentId = CreateEntityUnderRootPrefab(AZStd::string::format("EntityDepth%i", i), parentId);
EXPECT_EQ(modelDepth(), i + 1);
}
@@ -283,7 +283,7 @@ namespace AssetProcessor
ExcludeAssetRecognizer excludeRecogniser;
excludeRecogniser.m_name = "backup";
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
config.AddExcludeRecognizer(excludeRecogniser);
}
@@ -123,7 +123,7 @@ namespace AssetProcessor
ExcludeAssetRecognizer excludeRecogniser;
excludeRecogniser.m_name = "backup";
// we are excluding all the files in the folder but not the folder itself
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
m_assetScanner.get()->StartScan();
@@ -144,7 +144,7 @@ namespace AssetProcessor
ExcludeAssetRecognizer excludeRecogniser;
excludeRecogniser.m_name = "backup";
// we are excluding the complete folder here
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
m_assetScanner.get()->StartScan();
@@ -413,6 +413,8 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes)
auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular");
ASSERT_TRUE(configRoot);
UnitTestPlatformConfiguration config;
config.AddScanFolder(ScanFolderInfo("blahblah", "Blah ScanFolder", "sf2", true, true), true);
m_absorber.Clear();
ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false));
ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0);
@@ -347,7 +347,7 @@ namespace AssetProcessor
ExcludeAssetRecognizer excludeRecogniser;
excludeRecogniser.m_name = "backup";
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
config.AddExcludeRecognizer(excludeRecogniser);
AssetProcessorManager_Test apm(&config); // note, this will 'push' the scan folders in to the db.
@@ -1791,13 +1791,8 @@ namespace AssetProcessor
UNIT_TEST_EXPECT_TRUE((newfingerprintForPCAfterVersionChange != fingerprintForPC) || (newfingerprintForPCAfterVersionChange != newfingerprintForPC));//Fingerprints should be different
UNIT_TEST_EXPECT_TRUE((newfingerprintForANDROIDAfterVersionChange != fingerprintForANDROID) || (newfingerprintForANDROIDAfterVersionChange != newfingerprintForANDROID));//Fingerprints should be different
//------Test for Files which are excluded
processResults.clear();
absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder3/savebackup/test.txt"));
QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath));
UNIT_TEST_EXPECT_FALSE(BlockUntil(idling, 3000)); //Processing a file that will be excluded should not cause assetprocessor manager to emit the onBecameIdle signal because its state should not change
UNIT_TEST_EXPECT_TRUE(processResults.size() == 0);
// ------------- Test querying asset status -------------------
{
absolutePath = tempPath.absoluteFilePath("subfolder2/folder/ship.tiff");
@@ -1633,13 +1633,18 @@ namespace AssetProcessor
bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const
{
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
QString relPath, scanFolderName;
if (ConvertToRelativePath(fileName, relPath, scanFolderName))
{
if (excludeRecognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData()))
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
{
return true;
if (excludeRecognizer.m_patternMatcher.MatchesPath(relPath.toUtf8().constData()))
{
return true;
}
}
}
return false;
}
@@ -50,10 +50,10 @@
"order": 6000
},
"Exclude HoldFiles": {
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
},
"Exclude TempFiles": {
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
},
"RC i_caf": {
"glob": "*.i_caf",
@@ -74,10 +74,10 @@
"include": "test"
},
"Exclude HoldFiles": {
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
},
"Exclude TempFiles": {
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
},
"RC i_caf": {
"glob": "*.i_caf",
@@ -19,6 +19,7 @@ namespace O3DE::ProjectManager
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
return AZ::Success(QStringList{ ProjectCMakeCommand,
"-G", "Visual Studio 16 2019",
"-B", targetBuildPath,
"-S", m_projectInfo.m_path,
QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath),
@@ -77,7 +77,7 @@ namespace O3DE::ProjectManager
if (vsWhereFile.exists() && vsWhereFile.isFile())
{
QStringList vsWhereBaseArguments = QStringList{"-version",
"16.9.2",
"[16.9.2,17)",
"-latest",
"-requires",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"};
@@ -106,10 +106,8 @@ namespace O3DE::ProjectManager
}
return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.<br><br>"
"Visual Studio 2019 is required to build this project."
" Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>"
" or update to a newer version before proceeding to the next step."
" While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>."));
"A compatible version of Visual Studio is required to build this project.<br>"
"Refer to the <a href='https://o3de.org/docs/welcome-guide/requirements/#microsoft-visual-studio'>Visual Studio requirements</a> for more information."));
}
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
@@ -21,6 +21,7 @@
#include <QApplication>
#include <QDir>
#include <QMessageBox>
#include <QInputDialog>
namespace O3DE::ProjectManager
{
@@ -111,6 +112,11 @@ namespace O3DE::ProjectManager
}
}
if (!RegisterEngine(interactive))
{
return false;
}
const AZ::CommandLine* commandLine = GetCommandLine();
AZ_Assert(commandLine, "Failed to get command line");
@@ -165,6 +171,85 @@ namespace O3DE::ProjectManager
return m_entity != nullptr;
}
bool Application::RegisterEngine(bool interactive)
{
// get this engine's info
auto engineInfoOutcome = m_pythonBindings->GetEngineInfo();
if (!engineInfoOutcome)
{
if (interactive)
{
QMessageBox::critical(nullptr,
QObject::tr("Failed to get engine info"),
QObject::tr("A valid engine.json could not be found or loaded. "
"Please verify a valid engine.json file exists in %1")
.arg(GetEngineRoot()));
}
AZ_Error("Project Manager", false, "Failed to get engine info");
return false;
}
EngineInfo engineInfo = engineInfoOutcome.GetValue();
if (engineInfo.m_registered)
{
return true;
}
// check if an engine with this name is already registered and has a valid engine.json
auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name);
if (existingEngineResult)
{
if (!interactive)
{
AZ_Error("Project Manager", false, "An engine with the name %s is already registered with the path %s",
engineInfo.m_name.toUtf8().constData(), engineInfo.m_path.toUtf8().constData());
return false;
}
// get the updated engine name unless the user wants to cancel
bool okPressed = false;
const EngineInfo& otherEngineInfo = existingEngineResult.GetValue();
engineInfo.m_name = QInputDialog::getText(nullptr,
QObject::tr("Engine '%1' already registered").arg(engineInfo.m_name),
QObject::tr("An engine named '%1' is already registered.<br /><br />"
"<b>Current path</b><br />%2<br/><br />"
"<b>New path</b><br />%3<br /><br />"
"Press 'OK' to force registration, or provide a new engine name below.<br />"
"Alternatively, press `Cancel` to close the Project Manager and resolve the issue manually.")
.arg(engineInfo.m_name, otherEngineInfo.m_path, engineInfo.m_path),
QLineEdit::Normal,
engineInfo.m_name,
&okPressed);
if (!okPressed)
{
// user elected not to change the name or force registration
return false;
}
}
// always force register in case there is an engine registered in o3de_manifest.json, but
// the engine.json is missing or corrupt in which case GetEngineInfo() fails
constexpr bool forceRegistration = true;
auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration);
if (!registerOutcome)
{
if (interactive)
{
ProjectUtils::DisplayDetailedError(QObject::tr("Failed to register engine"), registerOutcome);
}
AZ_Error("Project Manager", false, "Failed to register engine %s : %s",
engineInfo.m_path.toUtf8().constData(), registerOutcome.GetError().first.c_str());
return false;
}
return true;
}
void Application::TearDown()
{
if (m_entity)
@@ -34,6 +34,7 @@ namespace O3DE::ProjectManager
private:
bool InitLog(const char* logName);
bool RegisterEngine(bool interactive);
AZStd::unique_ptr<PythonBindings> m_pythonBindings;
QSharedPointer<QCoreApplication> m_app;
@@ -25,13 +25,16 @@ namespace O3DE::ProjectManager
QString m_name;
QString m_thirdPartyPath;
// from o3de_manifest.json
QString m_path;
// from o3de_manifest.json
QString m_defaultProjectsFolder;
QString m_defaultGemsFolder;
QString m_defaultTemplatesFolder;
QString m_defaultRestrictedFolder;
bool m_registered = false;
bool IsValid() const;
};
} // namespace O3DE::ProjectManager
@@ -11,6 +11,7 @@
#include <FormFolderBrowseEditWidget.h>
#include <PythonBindingsInterface.h>
#include <PathValidator.h>
#include <ProjectUtils.h>
#include <AzQtComponents/Utilities/DesktopUtilities.h>
#include <QVBoxLayout>
@@ -114,10 +115,10 @@ namespace O3DE::ProjectManager
engineInfo.m_defaultGemsFolder = m_defaultGems->lineEdit()->text();
engineInfo.m_defaultTemplatesFolder = m_defaultProjectTemplates->lineEdit()->text();
bool result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo);
auto result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo);
if (!result)
{
QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to save engine settings."));
ProjectUtils::DisplayDetailedError(tr("Failed to save engine settings"), result, this);
}
}
else
@@ -14,6 +14,7 @@
#include <GemRepo/GemRepoInspector.h>
#include <PythonBindingsInterface.h>
#include <ProjectManagerDefs.h>
#include <ProjectUtils.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
@@ -92,8 +93,7 @@ namespace O3DE::ProjectManager
return;
}
AZ::Outcome < void,
AZStd::pair<AZStd::string, AZStd::string>> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
auto addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
if (addGemRepoResult.IsSuccess())
{
Reinit();
@@ -102,20 +102,7 @@ namespace O3DE::ProjectManager
else
{
QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri);
if (!addGemRepoResult.GetError().second.empty())
{
QMessageBox addRepoError;
addRepoError.setIcon(QMessageBox::Critical);
addRepoError.setWindowTitle(failureMessage);
addRepoError.setText(addGemRepoResult.GetError().first.c_str());
addRepoError.setDetailedText(addGemRepoResult.GetError().second.c_str());
addRepoError.exec();
}
else
{
QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().first.c_str());
}
ProjectUtils::DisplayDetailedError(failureMessage, addGemRepoResult, this);
AZ_Error("Project Manager", false, failureMessage.toUtf8());
}
}
@@ -659,5 +659,24 @@ namespace O3DE::ProjectManager
return AZ::Success(QString(projectBuildPath.c_str()));
}
void DisplayDetailedError(const QString& title, const AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>>& outcome, QWidget* parent)
{
const AZStd::string& generalError = outcome.GetError().first;
const AZStd::string& detailedError = outcome.GetError().second;
if (!detailedError.empty())
{
QMessageBox errorDialog(parent);
errorDialog.setIcon(QMessageBox::Critical);
errorDialog.setWindowTitle(title);
errorDialog.setText(generalError.c_str());
errorDialog.setDetailedText(detailedError.c_str());
errorDialog.exec();
}
else
{
QMessageBox::critical(parent, title, generalError.c_str());
}
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -98,5 +98,14 @@ namespace O3DE::ProjectManager
*/
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath);
/**
* Display a dialog with general and detailed sections for the given AZ::Outcome
* @param title Dialog title
* @param outcome The AZ::Outcome with general and detailed error messages
* @param parent Optional QWidget parent
*/
void DisplayDetailedError(const QString& title, const AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>>& outcome, QWidget* parent = nullptr);
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -312,6 +312,7 @@ namespace O3DE::ProjectManager
m_register = pybind11::module::import("o3de.register");
m_manifest = pybind11::module::import("o3de.manifest");
m_engineTemplate = pybind11::module::import("o3de.engine_template");
m_engineProperties = pybind11::module::import("o3de.engine_properties");
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
@@ -319,9 +320,6 @@ namespace O3DE::ProjectManager
m_repo = pybind11::module::import("o3de.repo");
m_pathlib = pybind11::module::import("pathlib");
// make sure the engine is registered
RegisterThisEngine();
m_pythonStarted = !PyErr_Occurred();
return m_pythonStarted;
}
@@ -346,36 +344,6 @@ namespace O3DE::ProjectManager
return !PyErr_Occurred();
}
bool PythonBindings::RegisterThisEngine()
{
bool registrationResult = true; // already registered is considered successful
bool pythonResult = ExecuteWithLock(
[&]
{
// check current engine path against all other registered engines
// to see if we are already registered
auto allEngines = m_manifest.attr("get_engines")();
if (pybind11::isinstance<pybind11::list>(allEngines))
{
for (auto engine : allEngines)
{
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine));
if (enginePath.Compare(m_enginePath) == 0)
{
return;
}
}
}
auto result = m_register.attr("register")(QString_To_Py_Path(QString(m_enginePath.c_str())));
registrationResult = (result.cast<int>() == 0);
});
bool finalResult = (registrationResult && pythonResult);
AZ_Assert(finalResult, "Registration of this engine failed!");
return finalResult;
}
AZ::Outcome<void, AZStd::string> PythonBindings::ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback)
{
if (!Py_IsInitialized())
@@ -407,16 +375,22 @@ namespace O3DE::ProjectManager
return ExecuteWithLockErrorHandling(executionCallback).IsSuccess();
}
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
EngineInfo PythonBindings::EngineInfoFromPath(pybind11::handle enginePath)
{
EngineInfo engineInfo;
bool result = ExecuteWithLock([&] {
auto enginePath = m_manifest.attr("get_this_engine_path")();
try
{
auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath);
if (pybind11::isinstance<pybind11::dict>(engineData))
{
engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0");
engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE");
engineInfo.m_path = Py_To_String(enginePath);
}
auto o3deData = m_manifest.attr("load_o3de_manifest")();
if (pybind11::isinstance<pybind11::dict>(o3deData))
{
engineInfo.m_path = Py_To_String(enginePath);
auto defaultGemsFolder = m_manifest.attr("get_o3de_gems_folder")();
engineInfo.m_defaultGemsFolder = Py_To_String_Optional(o3deData, "default_gems_folder", Py_To_String(defaultGemsFolder));
@@ -433,19 +407,62 @@ namespace O3DE::ProjectManager
engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "default_third_party_folder", Py_To_String(defaultThirdPartyFolder));
}
auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath);
if (pybind11::isinstance<pybind11::dict>(engineData))
// check if engine path is registered
auto allEngines = m_manifest.attr("get_engines")();
if (pybind11::isinstance<pybind11::list>(allEngines))
{
try
const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath));
for (auto engine : allEngines)
{
engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0");
engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE");
}
catch ([[maybe_unused]] const std::exception& e)
{
AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath));
AZ::IO::FixedMaxPath otherEnginePath(Py_To_String(engine));
if (otherEnginePath.Compare(enginePathFixed) == 0)
{
engineInfo.m_registered = true;
break;
}
}
}
}
catch ([[maybe_unused]] const std::exception& e)
{
AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath));
}
return engineInfo;
}
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
{
EngineInfo engineInfo;
bool result = ExecuteWithLock([&] {
auto enginePath = m_manifest.attr("get_this_engine_path")();
engineInfo = EngineInfoFromPath(enginePath);
});
if (!result || !engineInfo.IsValid())
{
return AZ::Failure();
}
else
{
return AZ::Success(AZStd::move(engineInfo));
}
}
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo(const QString& engineName)
{
EngineInfo engineInfo;
bool result = ExecuteWithLock([&] {
auto enginePathResult = m_manifest.attr("get_registered")(QString_To_Py_String(engineName));
// if a valid registered object is not found None is returned
if (!pybind11::isinstance<pybind11::none>(enginePathResult))
{
engineInfo = EngineInfoFromPath(enginePathResult);
// it is possible an engine is registered in o3de_manifest.json but the engine.json is
// missing or corrupt in which case we do not consider it a registered engine
}
});
if (!result || !engineInfo.IsValid())
@@ -458,10 +475,32 @@ namespace O3DE::ProjectManager
}
}
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
IPythonBindings::DetailedOutcome PythonBindings::SetEngineInfo(const EngineInfo& engineInfo, bool force)
{
bool result = ExecuteWithLock([&] {
auto registrationResult = m_register.attr("register")(
bool registrationSuccess = false;
bool pythonSuccess = ExecuteWithLock([&] {
EngineInfo currentEngine = EngineInfoFromPath(QString_To_Py_Path(engineInfo.m_path));
// be kind to source control and avoid needlessly updating engine.json
if (currentEngine.IsValid() &&
(currentEngine.m_name.compare(engineInfo.m_name) != 0 || currentEngine.m_version.compare(engineInfo.m_version) != 0))
{
auto enginePropsResult = m_engineProperties.attr("edit_engine_props")(
QString_To_Py_Path(engineInfo.m_path),
pybind11::none(), // existing engine_name
QString_To_Py_String(engineInfo.m_name),
QString_To_Py_String(engineInfo.m_version)
);
if (enginePropsResult.cast<int>() != 0)
{
// do not proceed with registration
return;
}
}
auto result = m_register.attr("register")(
QString_To_Py_Path(engineInfo.m_path),
pybind11::none(), // project_path
pybind11::none(), // gem_path
@@ -474,16 +513,22 @@ namespace O3DE::ProjectManager
QString_To_Py_Path(engineInfo.m_defaultGemsFolder),
QString_To_Py_Path(engineInfo.m_defaultTemplatesFolder),
pybind11::none(), // default_restricted_folder
QString_To_Py_Path(engineInfo.m_thirdPartyPath)
);
QString_To_Py_Path(engineInfo.m_thirdPartyPath),
pybind11::none(), // external_subdir_engine_path
pybind11::none(), // external_subdir_project_path
false, // remove
force
);
if (registrationResult.cast<int>() != 0)
{
result = false;
}
registrationSuccess = result.cast<int>() == 0;
});
return result;
if (pythonSuccess && registrationSuccess)
{
return AZ::Success();
}
return AZ::Failure<ErrorPair>(GetErrorPair());
}
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path, const QString& projectPath)
@@ -1064,7 +1109,7 @@ namespace O3DE::ProjectManager
return result && refreshResult;
}
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::AddGemRepo(const QString& repoUri)
IPythonBindings::DetailedOutcome PythonBindings::AddGemRepo(const QString& repoUri)
{
bool registrationResult = false;
bool result = ExecuteWithLock(
@@ -1080,7 +1125,7 @@ namespace O3DE::ProjectManager
if (!result || !registrationResult)
{
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
return AZ::Failure<IPythonBindings::ErrorPair>(GetErrorPair());
}
return AZ::Success();
@@ -1170,13 +1215,10 @@ namespace O3DE::ProjectManager
return gemRepoInfo;
}
//#define MOCK_GEM_REPO_INFO true
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> PythonBindings::GetAllGemRepoInfos()
{
QVector<GemRepoInfo> gemRepos;
#ifndef MOCK_GEM_REPO_INFO
auto result = ExecuteWithLockErrorHandling(
[&]
{
@@ -1189,18 +1231,6 @@ namespace O3DE::ProjectManager
{
return AZ::Failure<AZStd::string>(result.GetError().c_str());
}
#else
GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true);
mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna";
mockJohnRepo.m_repoUri = "https://github.com/o3de/o3de";
mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu.";
gemRepos.push_back(mockJohnRepo);
GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false);
mockJaneRepo.m_summary = "Jane's Summary.";
mockJaneRepo.m_repoUri = "https://github.com/o3de/o3de.org";
gemRepos.push_back(mockJaneRepo);
#endif // MOCK_GEM_REPO_INFO
std::sort(gemRepos.begin(), gemRepos.end());
return AZ::Success(AZStd::move(gemRepos));
@@ -1261,7 +1291,7 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemInfos));
}
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::DownloadGem(
IPythonBindings::DetailedOutcome PythonBindings::DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force)
{
// This process is currently limited to download a single gem at a time.
@@ -1290,12 +1320,12 @@ namespace O3DE::ProjectManager
if (!result.IsSuccess())
{
AZStd::pair<AZStd::string, AZStd::string> pythonRunError(result.GetError(), result.GetError());
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(AZStd::move(pythonRunError));
IPythonBindings::ErrorPair pythonRunError(result.GetError(), result.GetError());
return AZ::Failure<IPythonBindings::ErrorPair>(AZStd::move(pythonRunError));
}
else if (!downloadSucceeded)
{
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
return AZ::Failure<IPythonBindings::ErrorPair>(GetErrorPair());
}
return AZ::Success();
@@ -1322,13 +1352,13 @@ namespace O3DE::ProjectManager
return result && updateAvaliableResult;
}
AZStd::pair<AZStd::string, AZStd::string> PythonBindings::GetSimpleDetailedErrorPair()
IPythonBindings::ErrorPair PythonBindings::GetErrorPair()
{
AZStd::string detailedString = m_pythonErrorStrings.size() == 1
? ""
: AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string(""));
return AZStd::pair<AZStd::string, AZStd::string>(m_pythonErrorStrings.front(), detailedString);
return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString);
}
void PythonBindings::AddErrorString(AZStd::string errorString)
@@ -35,7 +35,8 @@ namespace O3DE::ProjectManager
// Engine
AZ::Outcome<EngineInfo> GetEngineInfo() override;
bool SetEngineInfo(const EngineInfo& engineInfo) override;
AZ::Outcome<EngineInfo> GetEngineInfo(const QString& engineName) override;
DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) override;
// Gem
AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) override;
@@ -62,12 +63,12 @@ namespace O3DE::ProjectManager
// Gem Repos
AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) override;
bool RefreshAllGemRepos() override;
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) override;
DetailedOutcome AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetGemInfosForRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetGemInfosForAllRepos() override;
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
DetailedOutcome DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) override;
void CancelDownload() override;
bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override;
@@ -80,14 +81,14 @@ namespace O3DE::ProjectManager
AZ::Outcome<void, AZStd::string> ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback);
bool ExecuteWithLock(AZStd::function<void()> executionCallback);
EngineInfo EngineInfoFromPath(pybind11::handle enginePath);
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
AZ::Outcome<void, AZStd::string> GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false);
bool RegisterThisEngine();
bool StopPython();
AZStd::pair<AZStd::string, AZStd::string> GetSimpleDetailedErrorPair();
IPythonBindings::ErrorPair GetErrorPair();
bool m_pythonStarted = false;
@@ -96,6 +97,7 @@ namespace O3DE::ProjectManager
AZStd::recursive_mutex m_lock;
pybind11::handle m_engineTemplate;
pybind11::handle m_engineProperties;
pybind11::handle m_cmake;
pybind11::handle m_register;
pybind11::handle m_manifest;
@@ -31,6 +31,10 @@ namespace O3DE::ProjectManager
IPythonBindings() = default;
virtual ~IPythonBindings() = default;
//! First string in pair is general error, second is detailed
using ErrorPair = AZStd::pair<AZStd::string, AZStd::string>;
using DetailedOutcome = AZ::Outcome<void, ErrorPair>;
/**
* Get whether Python was started or not. All Python functionality will fail if Python
* failed to start.
@@ -49,17 +53,25 @@ namespace O3DE::ProjectManager
// Engine
/**
* Get info about the engine
* Get info about the current engine
* @return an outcome with EngineInfo on success
*/
virtual AZ::Outcome<EngineInfo> GetEngineInfo() = 0;
/**
* Set info about the engine
* @param engineInfo an EngineInfo object
* Get info about an engine by name
* @param engineName The name of the engine to get info about
* @return an outcome with EngineInfo on success
*/
virtual bool SetEngineInfo(const EngineInfo& engineInfo) = 0;
virtual AZ::Outcome<EngineInfo> GetEngineInfo(const QString& engineName) = 0;
/**
* Set info about the engine
* @param force True to force registration even if an engine with the same name is already registered
* @param engineInfo an EngineInfo object
* @return a detailed error outcome on failure.
*/
virtual DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) = 0;
// Gems
@@ -202,7 +214,7 @@ namespace O3DE::ProjectManager
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return an outcome with a pair of string error and detailed messages on failure.
*/
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) = 0;
virtual DetailedOutcome AddGemRepo(const QString& repoUri) = 0;
/**
* Unregisters this gem repo with the current engine.
@@ -237,7 +249,7 @@ namespace O3DE::ProjectManager
* @param force should we forcibly overwrite the old version of the gem.
* @return an outcome with a pair of string error and detailed messages on failure.
*/
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
virtual DetailedOutcome DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) = 0;
/**
@@ -7,7 +7,7 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"PixelFormat": "ASTC_4x4",
"PixelFormat": "BC3",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -79,6 +79,7 @@ namespace ImageProcessingAtom
};
bool IsASTCFormat(EPixelFormat fmt);
bool IsHDRFormat(EPixelFormat fmt);
} // namespace ImageProcessingAtom
namespace AZ
@@ -620,6 +620,7 @@ namespace ImageProcessingAtom
{
PresetName emptyPreset;
//get file mask of this image file
AZStd::string fileMask = GetFileMask(imageFilePath);
@@ -636,8 +637,17 @@ namespace ImageProcessingAtom
}
if (outPreset == emptyPreset)
{
outPreset = m_defaultPreset;
{
auto image = IImageObjectPtr(LoadImageFromFile(imageFilePath));
if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent
|| image->GetAlphaContent() == EAlphaContent::eAlphaContent_OnlyWhite)
{
outPreset = m_defaultPreset;
}
else
{
outPreset = m_defaultPresetAlpha;
}
}
return outPreset;
@@ -78,7 +78,7 @@ namespace ImageProcessingAtom
return true;
}
astcenc_profile GetAstcProfile(bool isSrgb, EPixelFormat pixelFormat)
astcenc_profile GetAstcProfile(bool isSrgb, bool isHDR)
{
// select profile depends on LDR or HDR, SRGB or Linear
// ASTCENC_PRF_LDR
@@ -86,8 +86,6 @@ namespace ImageProcessingAtom
// ASTCENC_PRF_HDR_RGB_LDR_A
// ASTCENC_PRF_HDR
auto formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat);
bool isHDR = formatInfo->eSampleType == ESampleType::eSampleType_Half || formatInfo->eSampleType == ESampleType::eSampleType_Float;
astcenc_profile profile;
if (isHDR)
{
@@ -170,7 +168,7 @@ namespace ImageProcessingAtom
auto dstFormatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtDst);
const float quality = GetAstcCompressQuality(compressOption->compressQuality);
const astcenc_profile profile = GetAstcProfile(srcImage->HasImageFlags(EIF_SRGBRead), fmtSrc);
const astcenc_profile profile = GetAstcProfile(srcImage->HasImageFlags(EIF_SRGBRead), srcImage->HasImageFlags(EIF_HDR));
astcenc_config config;
astcenc_error status;
@@ -182,10 +180,12 @@ namespace ImageProcessingAtom
// Create a context based on the configuration
astcenc_context* context;
AZ::u32 blockCount = ((srcImage->GetWidth(0)+ dstFormatInfo->blockWidth-1)/dstFormatInfo->blockWidth) * ((srcImage->GetHeight(0) + dstFormatInfo->blockHeight-1)/dstFormatInfo->blockHeight);
AZ::u32 threadCount = AZStd::min(AZStd::thread::hardware_concurrency(), blockCount);
AZ::u32 threadCount = AZStd::min(AZStd::thread::hardware_concurrency()/2, blockCount);
status = astcenc_context_alloc(&config, threadCount, &context);
AZ_Assert( status == ASTCENC_SUCCESS, "ERROR: Codec context alloc failed: %s\n", astcenc_get_error_string(status));
AZ::Job* currentJob = AZ::JobContext::GetGlobalContext()->GetJobManager().GetCurrentJob();
const astcenc_type dataType =GetAstcDataType(fmtSrc);
// Compress the image for each mips
@@ -209,29 +209,65 @@ namespace ImageProcessingAtom
dstImage->GetImagePointer(mip, dstMem, dstPitch);
AZ::u32 dataSize = dstImage->GetMipBufSize(mip);
// Create jobs for each compression thread
auto completionJob = aznew AZ::JobCompletion();
for (AZ::u32 threadIdx = 0; threadIdx < threadCount; threadIdx++)
if (threadCount == 1)
{
const auto jobLambda = [&status, context, &image, &swizzle, dstMem, dataSize, threadIdx]()
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, 0);
if (error != ASTCENC_SUCCESS)
{
status = error;
}
}
else
{
AZ::JobCompletion* completionJob = nullptr;
if (!currentJob)
{
completionJob = aznew AZ::JobCompletion();
}
// Create jobs for each compression thread
for (AZ::u32 threadIdx = 0; threadIdx < threadCount; threadIdx++)
{
const auto jobLambda = [&status, context, &image, &swizzle, dstMem, dataSize, threadIdx]()
{
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, threadIdx);
if (error != ASTCENC_SUCCESS)
{
status = error;
}
};
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
// adds this job as child to current job if there is a current job
// otherwise adds it as a dependent for the complete job
if (currentJob)
{
currentJob->StartAsChild(simulationJob);
}
else
{
simulationJob->SetDependent(completionJob);
simulationJob->Start();
}
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, threadIdx);
if (error != ASTCENC_SUCCESS)
{
status = error;
}
};
}
if (currentJob)
{
currentJob->WaitForChildren();
}
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
simulationJob->SetDependent(completionJob);
simulationJob->Start();
}
if (completionJob)
{
completionJob->StartAndWaitForCompletion();
delete completionJob;
completionJob = nullptr;
if (completionJob)
{
completionJob->StartAndWaitForCompletion();
delete completionJob;
completionJob = nullptr;
}
}
if (status != ASTCENC_SUCCESS)
@@ -74,7 +74,7 @@ namespace ImageProcessingAtom
builderDescriptor.m_busId = azrtti_typeid<ImageBuilderWorker>();
builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_version = 26; // [ATOM-15086]
builderDescriptor.m_version = 27; // [ATOM-16958]
builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint();
m_imageBuilder.BusConnect(builderDescriptor.m_busId);
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
@@ -221,18 +221,19 @@ namespace ImageProcessingAtom
m_isShuttingDown = true;
}
PresetName GetImagePreset(const AZStd::string& filepath)
PresetName GetImagePreset(const AZStd::string& imageFileFullPath)
{
// first let preset from asset info
TextureSettings textureSettings;
StringOutcome output = TextureSettings::LoadTextureSetting(filepath, textureSettings);
AZStd::string settingFilePath = imageFileFullPath + TextureSettings::ExtensionName;
TextureSettings::LoadTextureSetting(settingFilePath, textureSettings);
if (!textureSettings.m_preset.IsEmpty())
{
return textureSettings.m_preset;
}
return BuilderSettingManager::Instance()->GetSuggestedPreset(filepath);
return BuilderSettingManager::Instance()->GetSuggestedPreset(imageFileFullPath);
}
void HandlePresetDependency(PresetName presetName, AZStd::vector<AssetBuilderSDK::SourceFileDependency>& sourceDependencyList)
@@ -283,6 +284,10 @@ namespace ImageProcessingAtom
return;
}
// Full path of the image file
AZStd::string fullPath;
AzFramework::StringFunc::Path::Join(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, true, true);
// Get the extension of the file
AZStd::string ext;
AzFramework::StringFunc::Path::GetExtension(request.m_sourceFile.c_str(), ext, false);
@@ -305,13 +310,12 @@ namespace ImageProcessingAtom
// add source dependency for .assetinfo file
AssetBuilderSDK::SourceFileDependency sourceFileDependency;
sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute;
sourceFileDependency.m_sourceFileDependencyPath = request.m_sourceFile;
AZ::StringFunc::Path::ReplaceExtension(sourceFileDependency.m_sourceFileDependencyPath, TextureSettings::ExtensionName);
sourceFileDependency.m_sourceFileDependencyPath = fullPath + TextureSettings::ExtensionName;
response.m_sourceFileDependencyList.push_back(sourceFileDependency);
// add source dependencies for .preset files
// Get the preset for this file
auto presetName = GetImagePreset(request.m_sourceFile);
// Get the preset for this file
auto presetName = GetImagePreset(fullPath.c_str());
HandlePresetDependency(presetName, response.m_sourceFileDependencyList);
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
@@ -8,6 +8,7 @@
#include <ImageLoader/ImageLoaders.h>
#include <Processing/ImageFlags.h>
#include <Atom/ImageProcessing/ImageObject.h>
// warning C4251: class QT_Type needs to have dll-interface to be used by clients of class 'QT_Type'
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
@@ -26,21 +27,31 @@ namespace ImageProcessingAtom
return nullptr;
}
IImageObject* loadedImage = nullptr;
if (TIFFLoader::IsExtensionSupported(ext.toUtf8()))
{
return TIFFLoader::LoadImageFromTIFF(filename);
loadedImage = TIFFLoader::LoadImageFromTIFF(filename);
}
else if (DdsLoader::IsExtensionSupported(ext.toUtf8()))
{
return DdsLoader::LoadImageFromFile(filename);
loadedImage = DdsLoader::LoadImageFromFile(filename);
}
else if (QtImageLoader::IsExtensionSupported(ext.toUtf8()))
{
return QtImageLoader::LoadImageFromFile(filename);
loadedImage = QtImageLoader::LoadImageFromFile(filename);
}
else if (ExrLoader::IsExtensionSupported(ext.toUtf8()))
{
return ExrLoader::LoadImageFromFile(filename);
loadedImage = ExrLoader::LoadImageFromFile(filename);
}
if (loadedImage)
{
if (IsHDRFormat(loadedImage->GetPixelFormat()))
{
loadedImage->AddImageFlags(EIF_HDR);
}
return loadedImage;
}
AZ_Warning("ImageProcessing", false, "No proper image loader to load file: %s", filename.c_str());
@@ -193,7 +193,7 @@ namespace ImageProcessingAtom
}
m_image->Get()->Swizzle(swizzle.c_str());
if (!m_input->m_presetSetting.m_discardAlpha)
if (m_input->m_presetSetting.m_discardAlpha)
{
m_alphaContent = EAlphaContent::eAlphaContent_Absent;
}
@@ -19,7 +19,7 @@ namespace ImageProcessingAtom
const static AZ::u32 EIF_Decal = 0x4; // this is usually set through the preset
const static AZ::u32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color
const static AZ::u32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture
const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use
const static AZ::u32 EIF_HDR = 0x40; // the image contains HDR data
const static AZ::u32 EIF_AttachedAlpha = 0x400; // deprecated: info for the engine: it's a texture with attached alpha channel
const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear)
const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized
@@ -52,6 +52,24 @@ namespace ImageProcessingAtom
return false;
}
bool IsHDRFormat(EPixelFormat fmt)
{
switch (fmt)
{
case ePixelFormat_BC6UH:
case ePixelFormat_R9G9B9E5:
case ePixelFormat_R32G32B32A32F:
case ePixelFormat_R32G32F:
case ePixelFormat_R32F:
case ePixelFormat_R16G16B16A16F:
case ePixelFormat_R16G16F:
case ePixelFormat_R16F:
return true;
default:
return false;
}
}
PixelFormatInfo::PixelFormatInfo(
uint32_t a_bitsPerPixel,
uint32_t a_Channels,
@@ -16,7 +16,9 @@ namespace AZ
AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0);
JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load(
void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
void* outputValue,
[[maybe_unused]] const Uuid& outputValueTypeId,
const rapidjson::Value& inputValue,
JsonDeserializerContext& context)
{
namespace JSR = JsonSerializationResult;
@@ -62,6 +64,7 @@ namespace AZ
LoadAny<AZ::Color>(propertyValue, inputPropertyPair.value, context, result) ||
LoadAny<AZStd::string>(propertyValue, inputPropertyPair.value, context, result) ||
LoadAny<AZ::Data::AssetId>(propertyValue, inputPropertyPair.value, context, result) ||
LoadAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, inputPropertyPair.value, context, result) ||
LoadAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, inputPropertyPair.value, context, result) ||
LoadAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, inputPropertyPair.value, context, result))
{
@@ -78,7 +81,10 @@ namespace AZ
}
JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store(
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId,
rapidjson::Value& outputValue,
const void* inputValue,
const void* defaultValue,
[[maybe_unused]] const Uuid& valueTypeId,
JsonSerializerContext& context)
{
namespace JSR = AZ::JsonSerializationResult;
@@ -138,9 +144,9 @@ namespace AZ
StoreAny<AZ::Color>(propertyValue, outputPropertyValue, context, result) ||
StoreAny<AZStd::string>(propertyValue, outputPropertyValue, context, result) ||
StoreAny<AZ::Data::AssetId>(propertyValue, outputPropertyValue, context, result) ||
StoreAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, outputPropertyValue, context, result) ||
StoreAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, outputPropertyValue, context, result) ||
StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(
propertyValue, outputPropertyValue, context, result))
StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, outputPropertyValue, context, result))
{
outputPropertyValueContainer.AddMember(
rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue,
@@ -164,7 +170,9 @@ namespace AZ
template<typename T>
bool JsonMaterialAssignmentSerializer::LoadAny(
AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
AZStd::any& propertyValue,
const rapidjson::Value& inputPropertyValue,
AZ::JsonDeserializerContext& context,
AZ::JsonSerializationResult::ResultCode& result)
{
if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type"))
@@ -187,7 +195,9 @@ namespace AZ
template<typename T>
bool JsonMaterialAssignmentSerializer::StoreAny(
const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
const AZStd::any& propertyValue,
rapidjson::Value& outputPropertyValue,
AZ::JsonSerializerContext& context,
AZ::JsonSerializationResult::ResultCode& result)
{
if (propertyValue.is<T>())
@@ -199,7 +209,7 @@ namespace AZ
result.Combine(StoreTypeId(typeValue, azrtti_typeid<T>(), context));
outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator());
T value = AZStd::any_cast<T>(propertyValue);
const T& value = AZStd::any_cast<T>(propertyValue);
result.Combine(
ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid<T>(), context));
return true;
@@ -25,21 +25,31 @@ namespace AZ
AZ_CLASS_ALLOCATOR_DECL;
JsonSerializationResult::Result Load(
void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
void* outputValue,
const Uuid& outputValueTypeId,
const rapidjson::Value& inputValue,
JsonDeserializerContext& context) override;
JsonSerializationResult::Result Store(
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId,
rapidjson::Value& outputValue,
const void* inputValue,
const void* defaultValue,
const Uuid& valueTypeId,
JsonSerializerContext& context) override;
private:
template<typename T>
bool LoadAny(
AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
AZStd::any& propertyValue,
const rapidjson::Value& inputPropertyValue,
AZ::JsonDeserializerContext& context,
AZ::JsonSerializationResult::ResultCode& result);
template<typename T>
bool StoreAny(
const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
const AZStd::any& propertyValue,
rapidjson::Value& outputPropertyValue,
AZ::JsonSerializerContext& context,
AZ::JsonSerializationResult::ResultCode& result);
};
} // namespace Render
@@ -204,23 +204,19 @@ namespace AZ
{
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
auto& device = static_cast<Device&>(GetDevice());
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
if (!groupData.IsAnyResourceTypeUpdated())
{
return RHI::ResultCode::Success;
}
if (m_constantBufferSize &&
groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
if (m_constantBufferSize)
{
memcpy(group.GetCompiledData().m_cpuConstantAddress, groupData.GetConstantData().data(), groupData.GetConstantData().size());
}
if (m_viewsDescriptorTableSize &&
groupData.IsResourceTypeEnabledForCompilation(
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask) |
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
if (m_viewsDescriptorTableSize)
{
//Lazy initialization for cbv/srv/uav Descriptor Tables
if (!group.m_viewsDescriptorTable.IsValid())
@@ -245,17 +241,12 @@ namespace AZ
UpdateViewsDescriptorTable(descriptorTable, groupData);
}
if (m_unboundedArrayCount &&
groupData.IsResourceTypeEnabledForCompilation(
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask) |
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask)))
if (m_unboundedArrayCount)
{
UpdateUnboundedArrayDescriptorTables(group, groupData);
}
if (m_samplersDescriptorTableSize &&
groupData.IsResourceTypeEnabledForCompilation(
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
if (m_samplersDescriptorTableSize)
{
const DescriptorTable descriptorTable(
group.m_samplersDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_samplersDescriptorTableSize,
@@ -61,10 +61,19 @@ namespace AZ
NSError* error = nil;
id<MTLLibrary> lib = nil;
bool loadFromByteCode = false;
// MacOS Big Sur (11.16.x) has issue loading some shader's byte code when GPUCapture(Metal) is on.
// Only enable it for Monterey (12.x)
if(@available(iOS 14.0, macOS 12.0, *))
{
loadFromByteCode = true;
}
const uint8_t* shaderByteCode = reinterpret_cast<const uint8_t*>(shaderFunction->GetByteCode().data());
const int byteCodeLength = shaderFunction->GetByteCode().size();
if(byteCodeLength > 0 )
if(byteCodeLength > 0 && loadFromByteCode)
{
dispatch_data_t dispatchByteCodeData = dispatch_data_create(shaderByteCode, byteCodeLength, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
lib = [mtlDevice newLibraryWithData:dispatchByteCodeData error:&error];
@@ -74,7 +83,7 @@ namespace AZ
//In case byte code was not generated try to create the lib with source code
MTLCompileOptions* compileOptions = [MTLCompileOptions alloc];
compileOptions.fastMathEnabled = YES;
compileOptions.languageVersion = MTLLanguageVersion2_0;
compileOptions.languageVersion = MTLLanguageVersion2_2;
lib = [mtlDevice newLibraryWithSource:source
options:compileOptions
error:&error];
@@ -6,7 +6,6 @@
*
*/
#include <AzCore/Debug/EventTrace.h>
#include <RHI/ArgumentBuffer.h>
#include <RHI/Conversions.h>
#include <RHI/Device.h>
@@ -62,57 +61,48 @@ namespace AZ
RHI::ResultCode ShaderResourceGroupPool::CompileGroupInternal(RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData)
{
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
group.UpdateCompiledDataIndex();
if (!groupData.IsAnyResourceTypeUpdated())
{
return RHI::ResultCode::Success;
}
group.UpdateCompiledDataIndex();
ArgumentBuffer& argBuffer = *group.m_compiledArgBuffers[group.m_compiledDataIndex];
argBuffer.ClearResourceTracking();
auto constantData = groupData.GetConstantData();
if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
if (!constantData.empty())
{
argBuffer.UpdateConstantBufferViews(groupData.GetConstantData());
}
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
uint32_t shaderInputIndex = 0;
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask)))
for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
{
for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
{
const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews = groupData.GetImageViewArray(imageInputIndex);
argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
++shaderInputIndex;
}
const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews = groupData.GetImageViewArray(imageInputIndex);
argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
++shaderInputIndex;
}
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
shaderInputIndex = 0;
for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
{
shaderInputIndex = 0;
for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
{
const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
AZStd::array_view<RHI::SamplerState> samplerStates = groupData.GetSamplerArray(samplerInputIndex);
argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
++shaderInputIndex;
}
const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
AZStd::array_view<RHI::SamplerState> samplerStates = groupData.GetSamplerArray(samplerInputIndex);
argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
++shaderInputIndex;
}
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
shaderInputIndex = 0;
for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
{
shaderInputIndex = 0;
for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
{
const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
++shaderInputIndex;
}
const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
++shaderInputIndex;
}
return RHI::ResultCode::Success;
@@ -6,6 +6,7 @@
*
*/
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/fixed_vector.h>
#include <AzCore/std/parallel/lock.h>
#include <RHI/Buffer.h>
#include <RHI/BufferView.h>
@@ -688,8 +689,8 @@ namespace AZ
if (interval != InvalidInterval)
{
uint32_t numBuffers = interval.m_max - interval.m_min + 1;
AZStd::vector<VkBuffer> nativeBuffers(numBuffers, VK_NULL_HANDLE);
AZStd::vector<VkDeviceSize> offsets(numBuffers, 0);
AZStd::fixed_vector<VkBuffer, RHI::Limits::Pipeline::StreamCountMax> nativeBuffers(numBuffers, VK_NULL_HANDLE);
AZStd::fixed_vector<VkDeviceSize, RHI::Limits::Pipeline::StreamCountMax> offsets(numBuffers, 0);
for (uint32_t i = 0; i < numBuffers; ++i)
{
const RHI::StreamBufferView& bufferView = streams[i + interval.m_min];
@@ -104,13 +104,13 @@ namespace AZ
RHI::ResultCode ShaderResourceGroupPool::CompileGroupInternal(RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData)
{
auto& group = static_cast<ShaderResourceGroup&>(groupBase);
group.UpdateCompiledDataIndex(m_currentIteration);
if (!groupData.IsAnyResourceTypeUpdated())
{
return RHI::ResultCode::Success;
}
group.UpdateCompiledDataIndex(m_currentIteration);
DescriptorSet& descriptorSet = *group.m_compiledData[group.GetCompileDataIndex()];
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
@@ -33,11 +33,13 @@ namespace AtomToolsFramework
{
if (value.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
{
const AZ::Data::Asset<AZ::RPI::ImageAsset>& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(
imageAsset.GetId(),
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
imageAsset.GetHint()));
const auto& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(imageAsset.GetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), imageAsset.GetHint()));
}
else if (value.Is<AZ::Data::Instance<AZ::RPI::Image>>())
{
const auto& image = value.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(image->GetAssetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>()));
}
return AZ::RPI::MaterialPropertyValue::ToAny(value);
@@ -6,7 +6,7 @@
// Sample Gems, Block source folders
// ------------------------------------------------------------------------------
"Exclude Work In Progress Folders": {
"pattern": ".*\\\\/.[Ss]rc\\\\/.*"
"pattern": "(^|.+/).[Ss]rc(/.*)?$"
}
}
}
@@ -1362,8 +1362,9 @@ namespace AZ::AtomBridge
// if 2d draw need to project pos to screen first
AzFramework::TextDrawParameters params;
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
params.m_position = AZ::Vector3(x, y, 1.0f);
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
params.m_color = m_rendState.m_color;
params.m_scale = AZ::Vector2(size);
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment
@@ -104,6 +104,7 @@ namespace AZ
MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config)
: m_configuration(config)
{
ConvertAssetsForSerialization();
}
void MaterialComponentController::Activate(EntityId entityId)
@@ -135,6 +136,7 @@ namespace AZ
void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config)
{
m_configuration = config;
ConvertAssetsForSerialization();
}
const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const
@@ -338,6 +340,7 @@ namespace AZ
// before LoadMaterials() is called [LYN-2249]
auto temp = m_configuration.m_materials;
m_configuration.m_materials = materials;
ConvertAssetsForSerialization();
LoadMaterials();
}
@@ -489,6 +492,7 @@ namespace AZ
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
ConvertAssetsForSerialization();
if (materialAssignment.RequiresLoading())
{
@@ -586,6 +590,7 @@ namespace AZ
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
materialAssignment.m_propertyOverrides = propertyOverrides;
ConvertAssetsForSerialization();
if (materialAssignment.RequiresLoading())
{
@@ -667,5 +672,33 @@ namespace AZ
TickBus::Handler::BusConnect();
}
}
void MaterialComponentController::ConvertAssetsForSerialization()
{
for (auto& materialAssignmentPair : m_configuration.m_materials)
{
MaterialAssignment& materialAssignment = materialAssignmentPair.second;
for (auto& propertyPair : materialAssignment.m_propertyOverrides)
{
auto& value = propertyPair.second;
if (value.is<AZ::Data::Asset<AZ::Data::AssetData>>())
{
value = AZStd::any_cast<AZ::Data::Asset<AZ::Data::AssetData>>(value).GetId();
}
else if (value.is<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>())
{
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(value).GetId();
}
else if (value.is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
{
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::ImageAsset>>(value).GetId();
}
else if (value.is<AZ::Data::Instance<AZ::RPI::Image>>())
{
value = AZStd::any_cast<AZ::Data::Instance<AZ::RPI::Image>>(value)->GetAssetId();
}
}
}
}
} // namespace Render
} // namespace AZ
@@ -99,6 +99,11 @@ namespace AZ
//! Queue material instance recreation notifiucations until tick
void QueueMaterialUpdateNotification();
//! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property
//! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying
//! problem is resolved.
void ConvertAssetsForSerialization();
EntityId m_entityId;
MaterialComponentConfig m_configuration;
AZStd::unordered_set<MaterialAssignmentId> m_materialsWithDirtyProperties;
@@ -11,6 +11,9 @@
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <Atom/RPI.Public/ViewportContextManager.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Base.h>
namespace AZ
{
@@ -199,7 +202,14 @@ namespace AZ
}
const char* LutAttachment = "LutOutput";
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{ "LutGenerationPass" };
auto renderPipelineName = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()
->GetDefaultViewportContext()
->GetCurrentPipeline()
->GetId();
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{
renderPipelineName.GetCStr(),
"LutGenerationPass"
};
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
@@ -3,10 +3,10 @@
"AssetProcessor": {
"Settings": {
"Exclude AudioProject": {
"pattern": ".*\\\\/Sounds\\\\/.+_project.*"
"pattern": "(^|.+/)Sounds/.+_project.*"
},
"Exclude AudioTemp": {
"pattern": ".*\\\\/Sounds\\\\/.+\\\\.(txt|xml|dat)"
"pattern": "(^|.+/)Sounds/.+\\\\.(txt|xml|dat)"
},
"RC audio": {
"pattern": ".*\\\\.(wav|pcm)",
@@ -10,6 +10,7 @@
"RC blastmaterial": {
"glob": "*.blastmaterial",
"params": "copy",
"critical": true,
"productAssetType": "{55F38C86-0767-4E7F-830A-A4BF624BE4DA}"
},
"RC blastconfiguration": {
@@ -91,17 +91,19 @@ namespace GraphCanvas
}
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
void GeneralNodeTitleComponent::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
{
m_title.SetFallback(title);
m_title = title;
m_subTitle = subtitle;
if (m_generalNodeTitleWidget)
{
m_generalNodeTitleWidget->SetTitle(title);
m_generalNodeTitleWidget->SetDetails(title, subtitle);
}
}
void GeneralNodeTitleComponent::SetTranslationKeyedTitle(const TranslationKeyedString& title)
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
{
m_title = title;
@@ -113,20 +115,10 @@ namespace GraphCanvas
AZStd::string GeneralNodeTitleComponent::GetTitle() const
{
return m_title.GetDisplayString();
return m_title;
}
void GeneralNodeTitleComponent::SetSubTitle(const AZStd::string& subtitle)
{
m_subTitle.SetFallback(subtitle);
if (m_generalNodeTitleWidget)
{
m_generalNodeTitleWidget->SetSubTitle(subtitle);
}
}
void GeneralNodeTitleComponent::SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle)
{
m_subTitle = subtitle;
@@ -138,7 +130,7 @@ namespace GraphCanvas
AZStd::string GeneralNodeTitleComponent::GetSubTitle() const
{
return m_subTitle.GetDisplayString();
return m_subTitle;
}
QGraphicsWidget* GeneralNodeTitleComponent::GetGraphicsWidget()
@@ -270,7 +262,23 @@ namespace GraphCanvas
SceneNotificationBus::Handler::BusDisconnect();
}
void GeneralNodeTitleGraphicsWidget::SetTitle(const TranslationKeyedString& title)
void GeneralNodeTitleGraphicsWidget::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
{
bool updateLayout = false;
if (m_titleWidget)
{
m_titleWidget->SetLabel(title);
updateLayout = true;
}
if (m_subTitleWidget)
{
m_subTitleWidget->SetLabel(subtitle);
updateLayout = true;
}
}
void GeneralNodeTitleGraphicsWidget::SetTitle(const AZStd::string& title)
{
if (m_titleWidget)
{
@@ -279,7 +287,7 @@ namespace GraphCanvas
}
}
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const TranslationKeyedString& subtitle)
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const AZStd::string& subtitle)
{
if (m_subTitleWidget)
{
@@ -19,7 +19,6 @@
#include <GraphCanvas/Components/StyleBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Types/EntitySaveData.h>
#include <GraphCanvas/Types/TranslationTypes.h>
#include <Widgets/GraphCanvasLabel.h>
namespace GraphCanvas
@@ -68,12 +67,11 @@ namespace GraphCanvas
////
// NodeTitleRequestBus
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle) override;
void SetTitle(const AZStd::string& title) override;
void SetTranslationKeyedTitle(const TranslationKeyedString& title) override;
AZStd::string GetTitle() const override;
void SetSubTitle(const AZStd::string& subtitle) override;
void SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle) override;
AZStd::string GetSubTitle() const override;
QGraphicsWidget* GetGraphicsWidget() override;
@@ -96,8 +94,8 @@ namespace GraphCanvas
private:
GeneralNodeTitleComponent(const GeneralNodeTitleComponent&) = delete;
TranslationKeyedString m_title;
TranslationKeyedString m_subTitle;
AZStd::string m_title;
AZStd::string m_subTitle;
AZStd::string m_basePalette;
@@ -123,9 +121,10 @@ namespace GraphCanvas
void Activate();
void Deactivate();
void SetTitle(const TranslationKeyedString& title);
void SetSubTitle(const TranslationKeyedString& subtitle);
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle);
void SetTitle(const AZStd::string& title);
void SetSubTitle(const AZStd::string& subtitle);
void SetPaletteOverride(AZStd::string_view paletteOverride);
void SetPaletteOverride(const AZ::Uuid& uuid);
@@ -1007,20 +1007,16 @@ namespace GraphCanvas
{
if (!configuration.m_name.empty())
{
cloneConfiguration->m_name.Clear();
cloneConfiguration->m_name.SetFallback(configuration.m_name);
cloneConfiguration->m_name = configuration.m_name;
}
else
{
AZStd::string nodeTitle;
NodeTitleRequestBus::EventResult(nodeTitle, configuration.m_targetEndpoint.GetNodeId(), &NodeTitleRequests::GetTitle);
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.GetDisplayString().c_str());
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.c_str());
// Gain some context. Lost the ability to refresh the strings.
// Should be fixable once we get an actual use case for this setup.
cloneConfiguration->m_name.Clear();
cloneConfiguration->m_name.SetFallback(displayName);
cloneConfiguration->m_name = displayName;
}
AZ::Entity* slotEntity = nullptr;
@@ -315,12 +315,6 @@ namespace GraphCanvas
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
}
void NodeComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
{
m_configuration.SetTooltip(tooltip.GetDisplayString());
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
}
void NodeComponent::AddSlot(const AZ::EntityId& slotId)
{
AZ_Assert(slotId.IsValid(), "Slot entity (ID: %s) is not valid!", slotId.ToString().data());
@@ -106,7 +106,6 @@ namespace GraphCanvas
// NodeRequestBus
void SetTooltip(const AZStd::string& tooltip) override;
void SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip) override;
const AZStd::string GetTooltip() const override { return m_configuration.GetTooltip(); }
void SetShowInOutliner(bool showInOutliner) override { m_configuration.SetShowInOutliner(showInOutliner); }
@@ -669,6 +669,7 @@ namespace GraphCanvas
{
GeometryNotificationBus::Handler::BusDisconnect();
SceneNotificationBus::Handler::BusDisconnect();
AZ::SystemTickBus::Handler::BusDisconnect();
}
void GestureSceneHelper::TrackElement(const AZ::EntityId& elementId)
@@ -337,12 +337,9 @@ namespace GraphCanvas
{
m_connectionType = slotRequests->GetConnectionType();
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
m_slotText->SetLabel(slotRequests->GetName());
m_slotText->SetLabel(slotName);
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
OnTooltipChanged(toolTip);
OnTooltipChanged(slotRequests->GetTooltip());
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
@@ -393,12 +390,12 @@ namespace GraphCanvas
AZ::SystemTickBus::Handler::BusConnect();
}
void DataSlotLayout::OnNameChanged(const TranslationKeyedString& name)
void DataSlotLayout::OnNameChanged(const AZStd::string& name)
{
m_slotText->SetLabel(name);
}
void DataSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
void DataSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
{
AZ::Uuid dataType;
DataSlotRequestBus::EventResult(dataType, m_owner.GetEntityId(), &DataSlotRequests::GetDataTypeId);
@@ -406,7 +403,7 @@ namespace GraphCanvas
AZStd::string typeString;
GraphModelRequestBus::EventResult(typeString, GetSceneId(), &GraphModelRequests::GetDataTypeString, dataType);
AZStd::string displayText = tooltip.GetDisplayString();
AZStd::string displayText = tooltip;
if (!typeString.empty())
{
@@ -486,7 +483,7 @@ namespace GraphCanvas
if (!iconPath.empty())
{
m_textDecoration = new GraphCanvasLabel();
m_textDecoration->SetLabel(iconPath, "", "");
m_textDecoration->SetLabel(iconPath);
m_textDecoration->setToolTip(toolTip.c_str());
ApplyTextStyle(m_textDecoration);
@@ -120,8 +120,8 @@ namespace GraphCanvas
// SlotNotificationBus
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
void OnNameChanged(const TranslationKeyedString&) override;
void OnTooltipChanged(const TranslationKeyedString&) override;
void OnNameChanged(const AZStd::string&) override;
void OnTooltipChanged(const AZStd::string&) override;
////
// StyleNotificationBus
@@ -58,13 +58,8 @@ namespace GraphCanvas
{
m_connectionType = slotRequests->GetConnectionType();
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
m_slotText->SetLabel(slotName);
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
OnTooltipChanged(toolTip);
m_slotText->SetLabel(slotRequests->GetName());
OnTooltipChanged(slotRequests->GetTooltip());
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
@@ -88,17 +83,15 @@ namespace GraphCanvas
OnStyleChanged();
}
void ExecutionSlotLayout::OnNameChanged(const TranslationKeyedString& name)
void ExecutionSlotLayout::OnNameChanged(const AZStd::string& name)
{
m_slotText->SetLabel(name);
}
void ExecutionSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
void ExecutionSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
{
AZStd::string displayText = tooltip.GetDisplayString();
m_slotConnectionPin->setToolTip(displayText.c_str());
m_slotText->setToolTip(displayText.c_str());
m_slotConnectionPin->setToolTip(tooltip.c_str());
m_slotText->setToolTip(tooltip.c_str());
}
void ExecutionSlotLayout::OnStyleChanged()
@@ -132,7 +125,7 @@ namespace GraphCanvas
if (!textDecoration.empty())
{
m_textDecoration = new GraphCanvasLabel();
m_textDecoration->SetLabel(textDecoration, "", "");
m_textDecoration->SetLabel(textDecoration);
m_textDecoration->setToolTip(toolTip.c_str());
ApplyTextStyle(m_textDecoration);
@@ -46,8 +46,8 @@ namespace GraphCanvas
// SlotNotificationBus
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
void OnNameChanged(const TranslationKeyedString& name) override;
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
void OnNameChanged(const AZStd::string& name) override;
void OnTooltipChanged(const AZStd::string& tooltip) override;
////
// StyleNotificationBus
@@ -119,13 +119,13 @@ namespace GraphCanvas
{
SlotRequestBus::EventResult(m_connectionType, m_owner.GetEntityId(), &SlotRequests::GetConnectionType);
TranslationKeyedString slotName;
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedName);
AZStd::string slotName;
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetName);
m_slotText->SetLabel(slotName);
TranslationKeyedString toolTip;
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedTooltip);
AZStd::string toolTip;
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTooltip);
OnTooltipChanged(toolTip);
@@ -151,17 +151,15 @@ namespace GraphCanvas
OnStyleChanged();
}
void ExtenderSlotLayout::OnNameChanged(const TranslationKeyedString& name)
void ExtenderSlotLayout::OnNameChanged(const AZStd::string& name)
{
m_slotText->SetLabel(name);
}
void ExtenderSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
void ExtenderSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
{
AZStd::string displayText = tooltip.GetDisplayString();
m_slotConnectionPin->setToolTip(displayText.c_str());
m_slotText->setToolTip(displayText.c_str());
m_slotConnectionPin->setToolTip(tooltip.c_str());
m_slotText->setToolTip(tooltip.c_str());
}
void ExtenderSlotLayout::OnStyleChanged()
@@ -48,8 +48,8 @@ namespace GraphCanvas
// SlotNotificationBus
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
void OnNameChanged(const TranslationKeyedString& name) override;
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
void OnNameChanged(const AZStd::string& name) override;
void OnTooltipChanged(const AZStd::string& tooltip) override;
////
// StyleNotificationBus
@@ -90,10 +90,10 @@ namespace GraphCanvas
TryAndSetupSlot();
}
void PropertySlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
void PropertySlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
{
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip));
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip));
}
void PropertySlotLayout::OnStyleChanged()
@@ -49,7 +49,7 @@ namespace GraphCanvas
// SlotNotificationBus
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
void OnTooltipChanged(const AZStd::string& tooltip) override;
////
// StyleNotificationBus
@@ -91,14 +91,6 @@ namespace GraphCanvas
void SlotComponent::Activate()
{
SetTranslationKeyedName(m_slotConfiguration.m_name);
// Default tooltip.
if (m_slotConfiguration.m_tooltip.empty())
{
SetTranslationKeyedTooltip(m_slotConfiguration.m_name);
}
SlotRequestBus::Handler::BusConnect(GetEntityId());
SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
}
@@ -171,24 +163,6 @@ namespace GraphCanvas
}
void SlotComponent::SetName(const AZStd::string& name)
{
if (name == m_slotConfiguration.m_name.GetDisplayString())
{
return;
}
m_slotConfiguration.m_name.SetFallback(name);
// Default tooltip.
if (m_slotConfiguration.m_tooltip.empty())
{
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
}
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
}
void SlotComponent::SetTranslationKeyedName(const TranslationKeyedString& name)
{
if (name == m_slotConfiguration.m_name)
{
@@ -206,25 +180,22 @@ namespace GraphCanvas
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
}
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
void SlotComponent::SetDetails(const AZStd::string& name, const AZStd::string& tooltip)
{
if (tooltip == m_slotConfiguration.m_tooltip.GetDisplayString())
if (name != m_slotConfiguration.m_name)
{
return;
m_slotConfiguration.m_name = name;
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
}
m_slotConfiguration.m_tooltip.SetFallback(tooltip);
// Default tooltip.
if (m_slotConfiguration.m_tooltip.empty())
if (tooltip != m_slotConfiguration.m_tooltip)
{
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
m_slotConfiguration.m_tooltip = tooltip;
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
}
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
}
void SlotComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
{
if (tooltip == m_slotConfiguration.m_tooltip)
{
@@ -521,8 +492,8 @@ namespace GraphCanvas
{
slotConfiguration.m_connectionType = GetConnectionType();
slotConfiguration.m_name = GetTranslationKeyedName();
slotConfiguration.m_tooltip = GetTranslationKeyedTooltip();
slotConfiguration.m_name = m_slotConfiguration.m_name;
slotConfiguration.m_tooltip = m_slotConfiguration.m_tooltip;
slotConfiguration.m_slotGroup = GetSlotGroup();
}
@@ -74,18 +74,14 @@ namespace GraphCanvas
Endpoint GetEndpoint() const override;
const AZStd::string GetName() const override { return m_slotConfiguration.m_name.GetDisplayString(); }
const AZStd::string GetName() const override { return m_slotConfiguration.m_name; }
void SetName(const AZStd::string& name) override;
TranslationKeyedString GetTranslationKeyedName() const override { return m_slotConfiguration.m_name; }
void SetTranslationKeyedName(const TranslationKeyedString&) override;
void SetDetails(const AZStd::string& name, const AZStd::string& tooltip) override;
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip.GetDisplayString(); }
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip; }
void SetTooltip(const AZStd::string& tooltip) override;
TranslationKeyedString GetTranslationKeyedTooltip() const override { return m_slotConfiguration.m_tooltip; }
void SetTranslationKeyedTooltip(const TranslationKeyedString&) override;
void DisplayProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
void RemoveProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
+18 -5
View File
@@ -58,7 +58,6 @@
#include <GraphCanvas/Types/ConstructPresets.h>
#include <GraphCanvas/Types/EntitySaveData.h>
#include <GraphCanvas/Types/TranslationTypes.h>
#include <GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h>
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
@@ -140,7 +139,6 @@ namespace GraphCanvas
Styling::DefaultSelector::Reflect(serializeContext);
Styling::CompoundSelector::Reflect(serializeContext);
Styling::NestedSelector::Reflect(serializeContext);
TranslationKeyedString::Reflect(serializeContext);
Styling::Style::Reflect(serializeContext);
AssetEditorUserSettings::Reflect(serializeContext);
}
@@ -218,6 +216,9 @@ namespace GraphCanvas
AzToolsFramework::ToolsAssetSystemBus::Broadcast(&AzToolsFramework::ToolsAssetSystemRequests::RegisterSourceAssetType, azrtti_typeid<TranslationAsset>(), TranslationAsset::GetFileFilter());
m_translationAssetWorker.Activate();
m_assetHandler = AZStd::make_unique<TranslationAssetHandler>();
m_assetHandler->Register();
}
}
@@ -376,15 +377,27 @@ namespace GraphCanvas
// Find any TranslationAsset files that may have translation database key/values
AZ::Data::AssetCatalogRequests::AssetEnumerationCB collectAssetsCb = [this](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo)
{
const auto assetType = azrtti_typeid<TranslationAsset>();
if (assetInfo.m_assetType == assetType)
if (AZ::StringFunc::EndsWith(assetInfo.m_relativePath, ".names", false))
{
m_translationAssets.push_back(assetId);
}
};
m_translationAssets.clear();
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, collectAssetsCb, postEnumerateCb);
}
void GraphCanvasSystemComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
AZ::Data::AssetInfo assetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId);
if (assetInfo.m_assetType == azrtti_typeid<TranslationAsset>())
{
GraphCanvas::TranslationRequestBus::Broadcast(&GraphCanvas::TranslationRequests::Restore);
}
}
void GraphCanvasSystemComponent::UnregisterAssetHandler()
{
if (m_assetHandler)
@@ -405,7 +418,7 @@ namespace GraphCanvas
for (const AZ::Data::AssetId& assetId : m_translationAssets)
{
AZ::Data::AssetBus::MultiHandler::BusConnect(assetId);
AZ::Data::AssetManager::Instance().GetAsset<TranslationAsset>(assetId, AZ::Data::AssetLoadBehavior::Default);
AZ::Data::AssetManager::Instance().GetAsset<TranslationAsset>(assetId, AZ::Data::AssetLoadBehavior::Default);
}
}
}
@@ -77,7 +77,10 @@ namespace GraphCanvas
AZ::EntityId CreateVirtualChild(const AZ::EntityId& real, const AZStd::string& virtualChildElement) const override;
////
// AzFramework::AssetCatalogEventBus::Handler
void OnCatalogLoaded(const char* /*catalogFile*/) override;
void OnCatalogAssetChanged(const AZ::Data::AssetId&) override;
////
AZStd::unique_ptr<TranslationAssetHandler> m_assetHandler;
@@ -195,7 +195,7 @@ namespace GraphCanvas
}
else
{
AZ_Error("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str());
AZ_Warning("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str());
}
}
}
@@ -59,14 +59,14 @@ namespace GraphCanvas
//!
//! Requirements:
//! - Must have a top level array called "entries"
//! - Must provide a "key" element for any entry added
//! - Must provide a "base" element for any entry added
//!
//! Example:
//!
//! {
//! "entries": [
//! {
//! "key": "Globals",
//! "base": "Globals",
//! "details": {
//! "name": "My Name",
//! "tooltip": "My Tooltip"
@@ -90,21 +90,21 @@ namespace GraphCanvas
//! Globals.details.somearray.0.name
//! Globals.details.somearray.1.name
//!
//! There is one important aspect however, if an element in an array has a "key" value, the value of this key
//! There is one important aspect however, if an element in an array has a "base" value, the value of this key
//! will replace the index. This is useful when the index and/or ordering of an entry is not relevant or may
//! change.
//!
//! "somearray": [ {
//! "name": "First one"
//! "key": "a_key"
//! "base": "a_key"
//! }, {
//! "name": "Second one",
//! "key": "b_key"
//! "base": "b_key"
//! } ]
//!
//! Globals.details.somearray.0.key == "a_key"
//! Globals.details.somearray.0.base == "a_key"
//! Globals.details.somearray.0.name == "First one"
//! Globals.details.somearray.1.key == "b_key"
//! Globals.details.somearray.1.base == "b_key"
//! Globals.details.somearray.1.name == "Second one"
//!
class TranslationAssetHandler
@@ -30,16 +30,7 @@ namespace GraphCanvas
void TranslationAssetWorker::Activate()
{
// Use AssetCatalog service to register ScriptCanvas asset type and extension
AZ::Data::AssetType assetType(azrtti_typeid<TranslationAsset>());
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddAssetType, assetType);
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, assetType);
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, TranslationAsset::GetFileFilter());
m_assetHandler = AZStd::make_unique<TranslationAssetHandler>();
if (!AZ::Data::AssetManager::Instance().GetHandler(assetType))
{
AZ::Data::AssetManager::Instance().RegisterHandler(m_assetHandler.get(), assetType);
}
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusConnect(GetUUID());
}
@@ -10,8 +10,10 @@
#include "TranslationAsset.h"
#include <AzCore/std/string/conversions.h>
#include <AzCore/StringFunc/StringFunc.h>
namespace GraphCanvas
{
namespace Translation
@@ -88,10 +90,16 @@ namespace GraphCanvas
static AZStd::string Sanitize(const AZStd::string& text)
{
AZStd::string result = text;
AZ::StringFunc::Replace(result, "*", "x");
AZ::StringFunc::Replace(result, "(", "_");
AZ::StringFunc::Replace(result, ")", "_");
AZ::StringFunc::Replace(result, "{", "_");
AZ::StringFunc::Replace(result, "}", "_");
AZ::StringFunc::Replace(result, ":", "_");
AZ::StringFunc::Replace(result, "<", "_");
AZ::StringFunc::Replace(result, ",", "_");
AZ::StringFunc::Replace(result, ">", " ");
AZ::StringFunc::Replace(result, "/", "");
AZ::StringFunc::Strip(result, " ");
AZ::StringFunc::Path::Normalize(result);
return result;
@@ -117,32 +125,32 @@ namespace GraphCanvas
virtual bool HasKey(const AZStd::string& /*key*/) { return false; }
//! Returns the text value for a given key
virtual const char* Get(const AZStd::string& /*key*/) { return nullptr; }
virtual bool Get(const AZStd::string& /*key*/, AZStd::string& /*value*/) { return false; }
struct Details
{
AZStd::string Name;
AZStd::string Tooltip;
AZStd::string Category;
AZStd::string Subtitle;
AZStd::string m_name;
AZStd::string m_tooltip;
AZStd::string m_category;
AZStd::string m_subtitle;
bool Valid = false;
bool m_valid = false;
Details() = default;
Details(const Details& rhs)
{
Name = rhs.Name;
Tooltip = rhs.Tooltip;
Subtitle = rhs.Subtitle;
Category = rhs.Category;
Valid = rhs.Valid;
m_name = rhs.m_name;
m_tooltip = rhs.m_tooltip;
m_category = rhs.m_category;
m_subtitle = rhs.m_subtitle;
m_valid = rhs.m_valid;
}
Details(const char* name, const char* tooltip, const char* subtitle, const char* category)
: Name(name), Tooltip(tooltip), Subtitle(subtitle), Category(category)
: m_name(name), m_tooltip(tooltip), m_subtitle(subtitle), m_category(category)
{
Valid = !Name.empty();
m_valid = !m_name.empty();
}
};
@@ -150,7 +158,7 @@ namespace GraphCanvas
virtual bool Add(const TranslationFormat& /*translationFormat*/) { return false; }
//! Get the details associated with a given key (assumes they are within a "details" object)
virtual Details GetDetails(const AZStd::string& /*key*/) { return Details(); }
virtual Details GetDetails(const AZStd::string& /*key*/, const Details& /*fallbackDetails*/) { return Details(); }
//! Generates the source JSON assets for all reflected elements
virtual void GenerateSourceAssets() {}
@@ -104,35 +104,49 @@ namespace GraphCanvas
return m_database.find(key) != m_database.end();
}
GraphCanvas::TranslationRequests::Details TranslationDatabase::GetDetails(const AZStd::string& key)
GraphCanvas::TranslationRequests::Details TranslationDatabase::GetDetails(const AZStd::string& key, const Details& fallbackDetails)
{
const char* name = Get(key + ".name");
const char* tooltip = Get(key + ".tooltip");
const char* subtitle = Get(key + ".subtitle");
const char* category = Get(key + ".category");
static bool s_traceMissingItems = true;
if (s_traceMissingItems)
Details details;
if (!Get(key + ".name", details.m_name))
{
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (name) not found for key: %s", key.c_str()).c_str());
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (tooltip) not found for key: %s", key.c_str()).c_str());
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (subtitle) not found for key: %s", key.c_str()).c_str());
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (category) not found for key: %s", key.c_str()).c_str());
details.m_name = fallbackDetails.m_name;
}
return Details(name ? name : "", tooltip ? tooltip : "", subtitle ? subtitle : "", category ? category : "");
if (!Get(key + ".tooltip", details.m_tooltip))
{
details.m_tooltip = fallbackDetails.m_tooltip;
}
if (!Get(key + ".subtitle", details.m_subtitle))
{
details.m_subtitle = fallbackDetails.m_subtitle;
}
if (!Get(key + ".category", details.m_category))
{
details.m_category = fallbackDetails.m_category;
}
return details;
}
const char* TranslationDatabase::Get(const AZStd::string& key)
bool TranslationDatabase::Get(const AZStd::string& key, AZStd::string& value)
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_mutex);
if (m_database.find(key) != m_database.end())
{
return m_database[key].c_str();
value = m_database[key];
return true;
}
return "";
static bool s_traceMissingItems = false;
if (s_traceMissingItems)
{
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value not found for key: %s", key.c_str()).c_str());
}
return false;
}
bool TranslationDatabase::Add(const TranslationFormat& format)
@@ -43,9 +43,9 @@ namespace GraphCanvas
bool HasKey(const AZStd::string& key) override;
TranslationRequests::Details GetDetails(const AZStd::string& key) override;
TranslationRequests::Details GetDetails(const AZStd::string& key, const Details& value) override;
const char* Get(const AZStd::string& key) override;
bool Get(const AZStd::string& key, AZStd::string& value) override;
bool Add(const TranslationFormat& format) override;
@@ -11,17 +11,6 @@
namespace GraphCanvas
{
namespace Schema
{
namespace Field
{
static constexpr char key[] = "key";
static constexpr char context[] = "context";
static constexpr char variant[] = "variant";
static constexpr char entries[] = "entries";
}
}
AZ_CLASS_ALLOCATOR_IMPL(TranslationFormatSerializer, AZ::SystemAllocator, 0);
void AddEntryToDatabase(const AZStd::string& baseKey, const AZStd::string& name, const rapidjson::Value& it, TranslationFormat* translationFormat)
@@ -35,8 +24,10 @@ namespace GraphCanvas
}
else
{
AZStd::string existingValue = translationFormat->m_database[finalKey.c_str()];
// There is a name collision
AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists", finalKey.c_str(), it.GetString());
AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists with value: %s (proposed: %s)", finalKey.c_str(), it.GetString(), existingValue.c_str(), it.GetString());
AZ_Error("TranslationSerializer", false, error.c_str());
}
}
@@ -74,8 +65,7 @@ namespace GraphCanvas
const rapidjson::Value& array = it;
for (rapidjson::SizeType i = 0; i < array.Size(); ++i)
{
// so, here, I need to go in and if there is a "key" member within the object, then I need to use that,
// if there isn't, I can use the %d
// if there is a "base" member within the object, then use it, otherwise use the index
if (array[i].IsObject())
{
if (array[i].HasMember(Schema::Field::key))
@@ -156,7 +146,7 @@ namespace GraphCanvas
AZStd::string baseKey = contextStr;
if (keyStr.empty())
{
AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str());
AZ_Warning("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str());
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key");
}
@@ -23,4 +23,15 @@ namespace GraphCanvas
AZ::JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue,
const void* defaultValue, const AZ::Uuid& valueTypeId, AZ::JsonSerializerContext& context) override;
};
namespace Schema
{
namespace Field
{
inline constexpr char key[] = "base";
inline constexpr char context[] = "context";
inline constexpr char variant[] = "variant";
inline constexpr char entries[] = "entries";
}
}
}

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