Merge branch 'stabilization/2110' into Prism/FixGemCart
This commit is contained in:
+1
-1
@@ -158,7 +158,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) ->
|
||||
else:
|
||||
cmd.append(f"--{key}")
|
||||
if append_defaults:
|
||||
cmd.append(f"--project-path={workspace.project}")
|
||||
cmd.append(f"--project-path={workspace.paths.project()}")
|
||||
return cmd
|
||||
|
||||
# ******
|
||||
|
||||
+55
-222
@@ -88,214 +88,6 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
bundler_batch_helper.call_bundles(help="")
|
||||
bundler_batch_helper.call_bundleSeed(help="")
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.assetpipeline
|
||||
@pytest.mark.test_case_id("C16877175")
|
||||
@pytest.mark.skip("'animations/animationeditorfiles/sample1.animgraph' missing, needs investigation")
|
||||
def test_WindowsAndMac_CreateAssetList_DependenciesCorrect(self, workspace, bundler_batch_helper):
|
||||
r"""
|
||||
Tests that an asset list created maps dependencies correctly.
|
||||
testdependencieslevel\level.pak and lists of known dependencies are used for validation
|
||||
|
||||
Test Steps:
|
||||
1. Create an asset list from the level.pak
|
||||
2. Create Lists of expected assets in the level.pak
|
||||
3. Add lists of expected assets to a single list
|
||||
4. Compare list of expected assets to actual assets
|
||||
"""
|
||||
helper = bundler_batch_helper
|
||||
|
||||
# Create the asset list file
|
||||
helper.call_assetLists(
|
||||
addSeed=r"levels\testdependencieslevel\level.pak",
|
||||
assetListFile=helper['asset_info_file_request']
|
||||
)
|
||||
|
||||
assert os.path.isfile(helper["asset_info_file_result"])
|
||||
|
||||
# Lists of known relative locations of assets
|
||||
default_level_assets = [
|
||||
"engineassets/texturemsg/defaultnouvs.dds",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.1",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.2",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.3",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.4",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.5",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.6",
|
||||
"engineassets/texturemsg/defaultnouvs.dds.7",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds.1",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds.2",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds.3",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds.4",
|
||||
"engineassets/texturemsg/defaultnouvs_ddn.dds.5",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds.1",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds.2",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds.3",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds.4",
|
||||
"engineassets/texturemsg/defaultnouvs_spec.dds.5",
|
||||
"engineassets/textures/defaults/16_grey.dds",
|
||||
"engineassets/textures/cubemap/default_level_cubemap.dds",
|
||||
"engineassets/textures/cubemap/default_level_cubemap.dds.1",
|
||||
"engineassets/textures/cubemap/default_level_cubemap.dds.2",
|
||||
"engineassets/textures/cubemap/default_level_cubemap.dds.3",
|
||||
"engineassets/textures/cubemap/default_level_cubemap.dds.4",
|
||||
"engineassets/textures/cubemap/default_level_cubemap_diff.dds",
|
||||
"engineassets/materials/water/ocean_default.mtl",
|
||||
"engineassets/textures/defaults/spot_default.dds",
|
||||
"engineassets/textures/defaults/spot_default.dds.1",
|
||||
"engineassets/textures/defaults/spot_default.dds.2",
|
||||
"engineassets/textures/defaults/spot_default.dds.3",
|
||||
"engineassets/textures/defaults/spot_default.dds.4",
|
||||
"engineassets/textures/defaults/spot_default.dds.5",
|
||||
"materials/material_terrain_default.mtl",
|
||||
"textures/skys/night/half_moon.dds",
|
||||
"textures/skys/night/half_moon.dds.1",
|
||||
"textures/skys/night/half_moon.dds.2",
|
||||
"textures/skys/night/half_moon.dds.3",
|
||||
"textures/skys/night/half_moon.dds.4",
|
||||
"textures/skys/night/half_moon.dds.5",
|
||||
"textures/skys/night/half_moon.dds.6",
|
||||
"engineassets/materials/sky/sky.mtl",
|
||||
"levels/testdependencieslevel/level.pak",
|
||||
"levels/testdependencieslevel/terrain/cover.ctc",
|
||||
"levels/testdependencieslevel/terraintexture.pak",
|
||||
]
|
||||
|
||||
sequence_material_cube_assets = [
|
||||
"textures/test_texture_sequence/test_texture_sequence000.dds",
|
||||
"textures/test_texture_sequence/test_texture_sequence001.dds",
|
||||
"textures/test_texture_sequence/test_texture_sequence002.dds",
|
||||
"textures/test_texture_sequence/test_texture_sequence003.dds",
|
||||
"textures/test_texture_sequence/test_texture_sequence004.dds",
|
||||
"textures/test_texture_sequence/test_texture_sequence005.dds",
|
||||
"objects/_primitives/_box_1x1.cgf",
|
||||
"materials/test_texture_sequence.mtl",
|
||||
"objects/_primitives/_box_1x1.mtl",
|
||||
"textures/_primitives/middle_gray_checker.dds",
|
||||
"textures/_primitives/middle_gray_checker.dds.1",
|
||||
"textures/_primitives/middle_gray_checker.dds.2",
|
||||
"textures/_primitives/middle_gray_checker.dds.3",
|
||||
"textures/_primitives/middle_gray_checker.dds.4",
|
||||
"textures/_primitives/middle_gray_checker.dds.5",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds.1",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds.2",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds.3",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds.4",
|
||||
"textures/_primitives/middle_gray_checker_ddn.dds.5",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds.1",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds.2",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds.3",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds.4",
|
||||
"textures/_primitives/middle_gray_checker_spec.dds.5",
|
||||
]
|
||||
|
||||
character_with_simplified_material_assets = [
|
||||
"objects/characters/jack/jack.actor",
|
||||
"objects/characters/jack/jack.mtl",
|
||||
"objects/characters/jack/textures/jack_diff.dds",
|
||||
"objects/characters/jack/textures/jack_diff.dds.1",
|
||||
"objects/characters/jack/textures/jack_diff.dds.2",
|
||||
"objects/characters/jack/textures/jack_diff.dds.3",
|
||||
"objects/characters/jack/textures/jack_diff.dds.4",
|
||||
"objects/characters/jack/textures/jack_diff.dds.5",
|
||||
"objects/characters/jack/textures/jack_diff.dds.6",
|
||||
"objects/characters/jack/textures/jack_diff.dds.7",
|
||||
"objects/characters/jack/textures/jack_spec.dds",
|
||||
"objects/characters/jack/textures/jack_spec.dds.1",
|
||||
"objects/characters/jack/textures/jack_spec.dds.2",
|
||||
"objects/characters/jack/textures/jack_spec.dds.3",
|
||||
"objects/characters/jack/textures/jack_spec.dds.4",
|
||||
"objects/characters/jack/textures/jack_spec.dds.5",
|
||||
"objects/characters/jack/textures/jack_spec.dds.6",
|
||||
"objects/characters/jack/textures/jack_spec.dds.7",
|
||||
"objects/default/editorprimitive.mtl",
|
||||
"engineassets/textures/grey.dds",
|
||||
"animations/animationeditorfiles/sample0.animgraph",
|
||||
"animations/motions/jack_death_fall_back_zup.motion",
|
||||
"animations/animationeditorfiles/sample1.animgraph",
|
||||
"animations/animationeditorfiles/sample0.motionset",
|
||||
"animations/motions/rin_jump.motion",
|
||||
"animations/animationeditorfiles/sample1.motionset",
|
||||
"animations/motions/rin_idle.motion",
|
||||
"animations/motions/jack_idle_aim_zup.motion",
|
||||
]
|
||||
|
||||
spawner_assets = [
|
||||
"slices/sphere.dynamicslice",
|
||||
"objects/default/primitive_sphere.cgf",
|
||||
"test1.luac",
|
||||
"test2.luac",
|
||||
]
|
||||
|
||||
ui_canvas_assets = [
|
||||
"fonts/vera.ttf",
|
||||
"fonts/vera.font",
|
||||
"scriptcanvas/mainmenu.scriptcanvas_compiled",
|
||||
"fonts/vera.fontfamily",
|
||||
"ui/canvas/start.uicanvas",
|
||||
"fonts/vera-italic.font",
|
||||
"ui/textureatlas/sample.texatlasidx",
|
||||
"fonts/vera-bold-italic.ttf",
|
||||
"fonts/vera-bold.font",
|
||||
"ui/textures/prefab/button_normal.dds",
|
||||
"ui/textures/prefab/button_normal.sprite",
|
||||
"fonts/vera-italic.ttf",
|
||||
"ui/textureatlas/sample.dds",
|
||||
"fonts/vera-bold-italic.font",
|
||||
"fonts/vera-bold.ttf",
|
||||
"ui/textures/prefab/button_disabled.dds",
|
||||
"ui/textures/prefab/button_disabled.sprite",
|
||||
]
|
||||
|
||||
wwise_and_atl_assets = [
|
||||
"libs/gameaudio/wwise/levels/testdependencieslevel/test_dependencies_level.xml",
|
||||
"sounds/wwise/test_bank3.bnk",
|
||||
"sounds/wwise/test_bank4.bnk",
|
||||
"sounds/wwise/test_bank5.bnk",
|
||||
"sounds/wwise/test_bank1.bnk",
|
||||
"sounds/wwise/init.bnk",
|
||||
"sounds/wwise/499820003.wem",
|
||||
"sounds/wwise/196049145.wem",
|
||||
]
|
||||
|
||||
particle_library_assets = [
|
||||
"libs/particles/milestone2particles.xml",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds.1",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds.2",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds.3",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds.4",
|
||||
"textures/milestone2/particles/fx_launchermuzzlering_01.dds.5",
|
||||
"textures/milestone2/particles/fx_sparkstreak_01.dds",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds.1",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds.2",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds.3",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds.4",
|
||||
"textures/milestone2/particles/fx_launchermuzzlefront_01.dds.5",
|
||||
]
|
||||
|
||||
lens_flares_library_assets = ["libs/flares/flares.xml", "textures/lights/flare01.dds"]
|
||||
|
||||
expected_assets_list = default_level_assets
|
||||
expected_assets_list.extend(sequence_material_cube_assets)
|
||||
expected_assets_list.extend(character_with_simplified_material_assets)
|
||||
expected_assets_list.extend(spawner_assets)
|
||||
expected_assets_list.extend(ui_canvas_assets)
|
||||
expected_assets_list.extend(wwise_and_atl_assets)
|
||||
expected_assets_list.extend(particle_library_assets)
|
||||
expected_assets_list.extend(lens_flares_library_assets) # All expected assets
|
||||
|
||||
# Get actual calculated dependencies from the asset list created
|
||||
actual_assets_list = []
|
||||
for rel_path in helper.get_asset_relative_paths(helper["asset_info_file_result"]):
|
||||
actual_assets_list.append(rel_path)
|
||||
|
||||
assert sorted(actual_assets_list) == sorted(expected_assets_list)
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.assetpipeline
|
||||
@@ -310,9 +102,9 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
3. Read and store contents of asset list into memory
|
||||
4. Attempt to create a new asset list in without using --allowOverwrites
|
||||
5. Verify that Asset Bundler returns false
|
||||
6. Verify that file contents of the orignally created asset list did not change from what was stored in memory
|
||||
6. Verify that file contents of the originally created asset list did not change from what was stored in memory
|
||||
7. Attempt to create a new asset list without debug while allowing overwrites
|
||||
8. Verify that file contents of the orignally created asset list changed from what was stored in memory
|
||||
8. Verify that file contents of the originally created asset list changed from what was stored in memory
|
||||
"""
|
||||
helper = bundler_batch_helper
|
||||
seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list
|
||||
@@ -919,7 +711,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
# Extra arguments for pattern comparison
|
||||
cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"])
|
||||
if workspace.project:
|
||||
cmd.append(f'--project-path={project_name}')
|
||||
cmd.append(f'--project-path={workspace.paths.project()}')
|
||||
return cmd
|
||||
# End generate_compare_command()
|
||||
|
||||
@@ -960,7 +752,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
output_mac_asset_list = helper.platform_file_name(last_output_arg, platform)
|
||||
|
||||
# Build execution command
|
||||
cmd = generate_compare_command(platform_arg, workspace.project)
|
||||
cmd = generate_compare_command(platform_arg, workspace.paths.project())
|
||||
|
||||
# Execute command
|
||||
subprocess.check_call(cmd)
|
||||
@@ -995,7 +787,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
f"--comparisonRulesFile={rule_file}",
|
||||
f"--comparisonType={args[1]}",
|
||||
r"--addComparison",
|
||||
f"--project-path={workspace.project}",
|
||||
f"--project-path={workspace.paths.project()}",
|
||||
]
|
||||
if args[1] == "4":
|
||||
# If pattern comparison, append a few extra arguments
|
||||
@@ -1117,7 +909,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
"--addDefaultSeedListFiles",
|
||||
"--platform=pc",
|
||||
"--print",
|
||||
f"--project-path={workspace.project}"
|
||||
f"--project-path={workspace.paths.project()}"
|
||||
],
|
||||
universal_newlines=True,
|
||||
)
|
||||
@@ -1189,7 +981,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
# Make sure file gets deleted on teardown
|
||||
request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False))
|
||||
|
||||
bundles_folder = os.path.join(workspace.paths.engine_root(), workspace.project, "Bundles")
|
||||
bundles_folder = os.path.join(workspace.paths.project(), "Bundles")
|
||||
level_pak = r"levels\testdependencieslevel\level.pak"
|
||||
bundle_request_path = os.path.join(bundles_folder, "bundle.pak")
|
||||
bundle_result_path = os.path.join(bundles_folder,
|
||||
@@ -1243,23 +1035,64 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
2. Verify file was created
|
||||
3. Verify that only the expected assets are present in the created asset list
|
||||
"""
|
||||
expected_assets = [
|
||||
expected_assets = sorted([
|
||||
"ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas",
|
||||
"ui/textures/prefab/button_normal.sprite"
|
||||
]
|
||||
"ui/textures/prefab/button_disabled.tif.streamingimage",
|
||||
"ui/textures/prefab/tooltip_sliced.tif.streamingimage",
|
||||
"ui/textures/prefab/button_normal.tif.streamingimage"
|
||||
])
|
||||
# Printing these lists out can save a step in debugging if this test fails on Jenkins.
|
||||
logger.info(f"expected_assets: {expected_assets}")
|
||||
|
||||
skip_assets = sorted([
|
||||
"ui/scripts/lyshineexamples/animation/multiplesequences.luac",
|
||||
"ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac",
|
||||
"fonts/vera.fontfamily",
|
||||
"fonts/vera-italic.font",
|
||||
"fonts/vera.font",
|
||||
"fonts/vera-bold.font",
|
||||
"fonts/vera-bold-italic.font",
|
||||
"fonts/vera-italic.ttf",
|
||||
"fonts/vera.ttf",
|
||||
"fonts/vera-bold.ttf",
|
||||
"fonts/vera-bold-italic.ttf"
|
||||
])
|
||||
logger.info(f"skip_assets: {skip_assets}")
|
||||
|
||||
expected_and_skip_assets = sorted(expected_assets + skip_assets)
|
||||
# Printing both together to make it quick to compare the results in the logs for a test failure on Jenkins
|
||||
logger.info(f"expected_and_skip_assets: {expected_and_skip_assets}")
|
||||
|
||||
# First, generate an asset info file without skipping, to get a list that can be used as a baseline to verify
|
||||
# the files were actually skipped, and not just missing.
|
||||
bundler_batch_helper.call_assetLists(
|
||||
assetListFile=bundler_batch_helper['asset_info_file_request'],
|
||||
addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas"
|
||||
)
|
||||
assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])
|
||||
assets_in_no_skip_list = []
|
||||
for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]):
|
||||
assets_in_no_skip_list.append(rel_path)
|
||||
assets_in_no_skip_list = sorted(assets_in_no_skip_list)
|
||||
logger.info(f"assets_in_no_skip_list: {assets_in_no_skip_list}")
|
||||
assert assets_in_no_skip_list == expected_and_skip_assets
|
||||
|
||||
# Now generate an asset info file using the skip command, and verify the skip files are not in the list.
|
||||
bundler_batch_helper.call_assetLists(
|
||||
assetListFile=bundler_batch_helper['asset_info_file_request'],
|
||||
addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas",
|
||||
skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac,"
|
||||
"ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font,"
|
||||
"fonts/vera.font,fonts/vera-bold.font,fonts/vera-bold-italic.font,fonts/vera-italic.ttf,fonts/vera.ttf,fonts/vera-bold.ttf,fonts/vera-bold-italic.ttf"
|
||||
allowOverwrites="",
|
||||
skip=','.join(skip_assets)
|
||||
)
|
||||
|
||||
assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])
|
||||
assets_in_list = []
|
||||
for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]):
|
||||
assets_in_list.append(rel_path)
|
||||
assets_in_list = sorted(assets_in_list)
|
||||
logger.info(f"assets_in_list: {assets_in_list}")
|
||||
assert assets_in_list == expected_assets
|
||||
|
||||
assert sorted(assets_in_list) == sorted(expected_assets)
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.assetpipeline
|
||||
|
||||
+3
@@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab
|
||||
);
|
||||
|
||||
m_backButton->setToolTip("Up one level (-)");
|
||||
|
||||
// Currently hide this button until we can correctly disable/enable it based on context.
|
||||
m_backButton->hide();
|
||||
}
|
||||
|
||||
void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()
|
||||
|
||||
@@ -140,7 +140,8 @@ namespace O3DE::ProjectManager
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemModel->index(0, 0);
|
||||
m_gemModel->GetSelectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -223,7 +224,7 @@ namespace O3DE::ProjectManager
|
||||
const bool gemFound = gemInfoHash.contains(gemName);
|
||||
if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index))
|
||||
{
|
||||
m_gemModel->removeRow(i);
|
||||
m_gemModel->RemoveGem(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -253,7 +254,7 @@ namespace O3DE::ProjectManager
|
||||
m_filterWidget->ResetAllFilters();
|
||||
|
||||
// Reselect the same selection to proc UI updates
|
||||
m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select);
|
||||
}
|
||||
|
||||
void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies)
|
||||
@@ -282,7 +283,7 @@ namespace O3DE::ProjectManager
|
||||
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
|
||||
{
|
||||
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex));
|
||||
GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, modelIndex, GemInfo::DownloadStatus::Downloading);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +315,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex);
|
||||
m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_gemListView->scrollTo(proxyIndex);
|
||||
|
||||
m_rightPanelStack->setCurrentIndex(RightPanelWidgetOrder::Inspector);
|
||||
@@ -378,6 +379,9 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString selectedGemPath = m_gemModel->GetPath(modelIndex);
|
||||
|
||||
// Remove gem from gems to be added
|
||||
GemModel::SetIsAdded(*m_gemModel, modelIndex, false);
|
||||
|
||||
// Unregister the gem
|
||||
auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath);
|
||||
if (!unregisterResult)
|
||||
@@ -386,8 +390,10 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString selectedGemName = m_gemModel->GetName(modelIndex);
|
||||
|
||||
// Remove gem from model
|
||||
m_gemModel->removeRow(modelIndex.row());
|
||||
m_gemModel->RemoveGem(modelIndex);
|
||||
|
||||
// Delete uninstalled gem directory
|
||||
if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true))
|
||||
@@ -398,6 +404,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// Show undownloaded remote gem again
|
||||
Refresh();
|
||||
|
||||
// Select remote gem
|
||||
QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName);
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -592,7 +603,8 @@ namespace O3DE::ProjectManager
|
||||
if (succeeded)
|
||||
{
|
||||
// refresh the information for downloaded gems
|
||||
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
|
||||
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult =
|
||||
PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
|
||||
if (allGemInfosResult.IsSuccess())
|
||||
{
|
||||
// we should find the gem name now in all gem infos
|
||||
@@ -600,15 +612,33 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (gemInfo.m_name == gemName)
|
||||
{
|
||||
QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (index.isValid())
|
||||
QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (oldIndex.isValid())
|
||||
{
|
||||
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus);
|
||||
m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath);
|
||||
m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink);
|
||||
// Check if old gem is selected
|
||||
bool oldGemSelected = false;
|
||||
if (m_gemModel->GetSelectionModel()->currentIndex() == oldIndex)
|
||||
{
|
||||
oldGemSelected = true;
|
||||
}
|
||||
|
||||
// Remove old remote gem
|
||||
m_gemModel->RemoveGem(oldIndex);
|
||||
|
||||
// Add new downloaded version of gem
|
||||
QModelIndex newIndex = m_gemModel->AddGem(gemInfo);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, newIndex, GemInfo::DownloadSuccessful);
|
||||
GemModel::SetIsAdded(*m_gemModel, newIndex, true);
|
||||
|
||||
// Select new version of gem if it was previously selected
|
||||
if (oldGemSelected)
|
||||
{
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(newIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -618,7 +648,7 @@ namespace O3DE::ProjectManager
|
||||
QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (index.isValid())
|
||||
{
|
||||
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ namespace O3DE::ProjectManager
|
||||
return m_selectionModel;
|
||||
}
|
||||
|
||||
void GemModel::AddGem(const GemInfo& gemInfo)
|
||||
QModelIndex GemModel::AddGem(const GemInfo& gemInfo)
|
||||
{
|
||||
if (FindIndexByNameString(gemInfo.m_name).isValid())
|
||||
{
|
||||
// do not add gems with duplicate names
|
||||
// this can happen by mistake or when a gem repo has a gem with the same name as a local gem
|
||||
AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData());
|
||||
return;
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QStandardItem* item = new QStandardItem();
|
||||
@@ -67,6 +67,22 @@ namespace O3DE::ProjectManager
|
||||
|
||||
const QModelIndex modelIndex = index(rowCount()-1, 0);
|
||||
m_nameToIndexMap[gemInfo.m_name] = modelIndex;
|
||||
|
||||
return modelIndex;
|
||||
}
|
||||
|
||||
void GemModel::RemoveGem(const QModelIndex& modelIndex)
|
||||
{
|
||||
removeRow(modelIndex.row());
|
||||
}
|
||||
|
||||
void GemModel::RemoveGem(const QString& gemName)
|
||||
{
|
||||
auto nameFind = m_nameToIndexMap.find(gemName);
|
||||
if (nameFind != m_nameToIndexMap.end())
|
||||
{
|
||||
removeRow(nameFind->row());
|
||||
}
|
||||
}
|
||||
|
||||
void GemModel::Clear()
|
||||
@@ -391,11 +407,11 @@ namespace O3DE::ProjectManager
|
||||
// Select a valid row if currently selected row was removed
|
||||
if (selectedRowRemoved)
|
||||
{
|
||||
for (const QModelIndex& index : m_nameToIndexMap)
|
||||
for (const QModelIndex& index : m_nameToIndexMap)
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
|
||||
GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,9 @@ namespace O3DE::ProjectManager
|
||||
RoleRepoUri
|
||||
};
|
||||
|
||||
void AddGem(const GemInfo& gemInfo);
|
||||
QModelIndex AddGem(const GemInfo& gemInfo);
|
||||
void RemoveGem(const QModelIndex& modelIndex);
|
||||
void RemoveGem(const QString& gemName);
|
||||
void Clear();
|
||||
void UpdateGemDependencies();
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace O3DE::ProjectManager
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
|
||||
m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
Gem::Atom_RPI.Public
|
||||
Gem::Atom_RHI.Public
|
||||
Gem::Atom_RPI.Edit
|
||||
Gem::Atom_Utils.TestUtils.Static
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Gem::Atom_RPI.Tests
|
||||
|
||||
@@ -209,10 +209,6 @@ namespace AZ
|
||||
//! Traversal will stop once all properties have been enumerated or the callback function returns false
|
||||
void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const;
|
||||
|
||||
//! Convert the property value into the format that will be stored in the source data
|
||||
//! This is primarily needed to support conversions of special types like enums and images
|
||||
bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const;
|
||||
|
||||
Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const;
|
||||
|
||||
//! Possibly renames @propertyId based on the material version update steps.
|
||||
|
||||
@@ -300,48 +300,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const
|
||||
{
|
||||
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is<uint32_t>())
|
||||
{
|
||||
const uint32_t index = propertyValue.GetValue<uint32_t>();
|
||||
if (index >= propertyDefinition.m_enumValues.size())
|
||||
{
|
||||
AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyValue = propertyDefinition.m_enumValues[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Image asset references must be converted from asset IDs to a relative source file path
|
||||
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is<Data::Asset<ImageAsset>>())
|
||||
{
|
||||
const Data::Asset<ImageAsset>& imageAsset = propertyValue.GetValue<Data::Asset<ImageAsset>>();
|
||||
|
||||
Data::AssetInfo imageAssetInfo;
|
||||
if (imageAsset.GetId().IsValid())
|
||||
{
|
||||
bool result = false;
|
||||
AZStd::string rootFilePath;
|
||||
const AZStd::string platformName = ""; // Empty for default
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById,
|
||||
imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath);
|
||||
if (!result)
|
||||
{
|
||||
AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
propertyValue = imageAssetInfo.m_relativePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialTypeAsset>> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const
|
||||
{
|
||||
MaterialTypeAssetCreator materialTypeAssetCreator;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <Common/AssetManagerTestFixture.h>
|
||||
#include <Common/RHI/Stubs.h>
|
||||
#include <Common/RHI/Factory.h>
|
||||
#include <Common/AssetSystemStub.h>
|
||||
#include <Atom/Utils/TestUtils/AssetSystemStub.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
|
||||
@@ -10,8 +10,6 @@ set(FILES
|
||||
Tests/Buffer/BufferTests.cpp
|
||||
Tests/Common/AssetManagerTestFixture.cpp
|
||||
Tests/Common/AssetManagerTestFixture.h
|
||||
Tests/Common/AssetSystemStub.cpp
|
||||
Tests/Common/AssetSystemStub.h
|
||||
Tests/Common/ErrorMessageFinder.cpp
|
||||
Tests/Common/ErrorMessageFinder.h
|
||||
Tests/Common/ErrorMessageFinderTests.cpp
|
||||
|
||||
@@ -61,3 +61,31 @@ ly_add_target(
|
||||
PRIVATE
|
||||
Gem::AtomToolsFramework.Static
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
################################################################################
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
ly_add_target(
|
||||
NAME AtomToolsFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
atomtoolsframework_tests_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Tests
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::AtomToolsFramework.Static
|
||||
Gem::Atom_Utils.TestUtils.Static
|
||||
)
|
||||
|
||||
ly_add_googletest(
|
||||
NAME Gem::AtomToolsFramework.Tests
|
||||
)
|
||||
|
||||
endif()
|
||||
+23
-3
@@ -7,11 +7,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -35,12 +36,31 @@ namespace AtomToolsFramework
|
||||
//! Convert and assign material property meta data fields to editor dynamic property configuration
|
||||
void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData);
|
||||
|
||||
//! Convert and assign editor dynamic property configuration fields to material property meta data
|
||||
//! Convert and assign editor dynamic property configuration fields to material property meta data
|
||||
void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig);
|
||||
|
||||
//! Compare equality of data types and values of editor property stored in AZStd::any
|
||||
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB);
|
||||
|
||||
//! Convert the property value into the format that will be stored in the source data
|
||||
//! This is primarily needed to support conversions of special types like enums and images
|
||||
//! @param exportPath absolute path of the file being saved
|
||||
//! @param propertyDefinition describes type information and other details about propertyValue
|
||||
//! @param propertyValue the value being converted before saving
|
||||
bool ConvertToExportFormat(
|
||||
const AZStd::string& exportPath,
|
||||
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
|
||||
AZ::RPI::MaterialPropertyValue& propertyValue);
|
||||
|
||||
//! Generate a file path from the exported file to the external reference.
|
||||
//! This function returns a relative path from the export file to the reference file.
|
||||
//! If the relative path is too different or distant from the export path then we return the asset folder relative path.
|
||||
//! @param exportPath absolute path of the file being saved
|
||||
//! @param referencePath absolute path of a file that will be treated as an external reference
|
||||
//! @param maxPathDepth the maximum relative depth or number of parent or child folders between the export path and the reference path
|
||||
AZStd::string GetExteralReferencePath(
|
||||
const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2);
|
||||
|
||||
//! Traverse up the instance data node hierarchy to find the containing dynamic property object
|
||||
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode);
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Reflect/Image/ImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
@@ -163,6 +165,88 @@ namespace AtomToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConvertToExportFormat(
|
||||
const AZStd::string& exportPath,
|
||||
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
|
||||
AZ::RPI::MaterialPropertyValue& propertyValue)
|
||||
{
|
||||
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is<uint32_t>())
|
||||
{
|
||||
const uint32_t index = propertyValue.GetValue<uint32_t>();
|
||||
if (index >= propertyDefinition.m_enumValues.size())
|
||||
{
|
||||
AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyValue = propertyDefinition.m_enumValues[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Image asset references must be converted from asset IDs to a relative source file path
|
||||
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image)
|
||||
{
|
||||
if (propertyValue.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
|
||||
{
|
||||
const auto& imageAsset = propertyValue.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
|
||||
const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId());
|
||||
propertyValue = GetExteralReferencePath(exportPath, imagePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (propertyValue.Is<AZ::Data::Instance<AZ::RPI::Image>>())
|
||||
{
|
||||
const auto& image = propertyValue.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
|
||||
const auto& imagePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : "";
|
||||
propertyValue = GetExteralReferencePath(exportPath, imagePath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string GetExteralReferencePath(const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth)
|
||||
{
|
||||
if (referencePath.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::IO::BasicPath<AZStd::string> exportFolder(exportPath);
|
||||
exportFolder.RemoveFilename();
|
||||
|
||||
const AZStd::string relativePath = AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix();
|
||||
|
||||
// Count the difference in depth between the export file path and the referenced file path.
|
||||
uint32_t parentFolderCount = 0;
|
||||
AZStd::string::size_type pos = 0;
|
||||
const AZStd::string parentFolderToken = "..";
|
||||
while ((pos = relativePath.find(parentFolderToken, pos)) != AZStd::string::npos)
|
||||
{
|
||||
parentFolderCount++;
|
||||
pos += parentFolderToken.length();
|
||||
}
|
||||
|
||||
// If the difference in depth is too great then revert to using the asset folder relative path.
|
||||
// We could change this to only use relative paths for references in subfolders.
|
||||
if (parentFolderCount > maxPathDepth)
|
||||
{
|
||||
AZStd::string watchFolder;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
bool sourceInfoFound = false;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(),
|
||||
assetInfo, watchFolder);
|
||||
if (sourceInfoFound)
|
||||
{
|
||||
return assetInfo.m_relativePath;
|
||||
}
|
||||
}
|
||||
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode)
|
||||
{
|
||||
// Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property
|
||||
@@ -172,7 +256,8 @@ namespace AtomToolsFramework
|
||||
const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata();
|
||||
if (context && classData)
|
||||
{
|
||||
if (context->CanDowncast(classData->m_typeId, azrtti_typeid<AtomToolsFramework::DynamicProperty>(), classData->m_azRtti, nullptr))
|
||||
if (context->CanDowncast(
|
||||
classData->m_typeId, azrtti_typeid<AtomToolsFramework::DynamicProperty>(), classData->m_azRtti, nullptr))
|
||||
{
|
||||
return static_cast<const AtomToolsFramework::DynamicProperty*>(currentNode->FirstInstance());
|
||||
}
|
||||
|
||||
@@ -7,25 +7,71 @@
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <Atom/Utils/TestUtils/AssetSystemStub.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
|
||||
class AtomToolsFrameworkTest
|
||||
: public ::testing::Test
|
||||
namespace UnitTest
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
class AtomToolsFrameworkTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create(AZ::SystemAllocator::Descriptor());
|
||||
}
|
||||
|
||||
m_assetSystemStub.Activate();
|
||||
|
||||
RegisterSourceAsset("objects/upgrades/materials/supercondor.material");
|
||||
RegisterSourceAsset("materials/condor.material");
|
||||
RegisterSourceAsset("materials/talisman.material");
|
||||
RegisterSourceAsset("materials/city.material");
|
||||
RegisterSourceAsset("materials/totem.material");
|
||||
RegisterSourceAsset("textures/orange.png");
|
||||
RegisterSourceAsset("textures/red.png");
|
||||
RegisterSourceAsset("textures/gold.png");
|
||||
RegisterSourceAsset("textures/fuzz.png");
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_assetSystemStub.Deactivate();
|
||||
|
||||
if (AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterSourceAsset(const AZStd::string& path)
|
||||
{
|
||||
const AZ::IO::BasicPath assetRootPath = AZ::IO::PathView(m_assetRoot).LexicallyNormal();
|
||||
const AZ::IO::BasicPath normalizedPath = AZ::IO::BasicPath(assetRootPath).Append(path).LexicallyNormal();
|
||||
|
||||
AZ::Data::AssetInfo assetInfo = {};
|
||||
assetInfo.m_assetId = AZ::Uuid::CreateRandom();
|
||||
assetInfo.m_relativePath = normalizedPath.LexicallyRelative(assetRootPath).StringAsPosix();
|
||||
m_assetSystemStub.RegisterSourceInfo(normalizedPath.StringAsPosix().c_str(), assetInfo, assetRootPath.StringAsPosix().c_str());
|
||||
}
|
||||
|
||||
static constexpr const char* m_assetRoot = "d:/project/assets/";
|
||||
AssetSystemStub m_assetSystemStub;
|
||||
};
|
||||
|
||||
TEST_F(AtomToolsFrameworkTest, GetExteralReferencePath_Succeeds)
|
||||
{
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("", "", 2), "");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/condor.material", "", 2), "");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "", 2), "");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 2), "../textures/gold.png");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 0), "textures/gold.png");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 3), "../../../materials/condor.material");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 2), "materials/condor.material");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 1), "materials/condor.material");
|
||||
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material");
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AtomToolsFrameworkTest, SanityTest)
|
||||
{
|
||||
ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/AtomToolsFrameworkTest.cpp
|
||||
)
|
||||
@@ -230,18 +230,13 @@ namespace MaterialEditor
|
||||
|
||||
// create source data from properties
|
||||
MaterialSourceData sourceData;
|
||||
sourceData.m_materialType = m_materialSourceData.m_materialType;
|
||||
sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial;
|
||||
|
||||
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
|
||||
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
|
||||
|
||||
// Force save data to store forward slashes
|
||||
AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/");
|
||||
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
|
||||
sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_materialType);
|
||||
sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial);
|
||||
|
||||
// populate sourceData with modified or overwritten properties
|
||||
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) {
|
||||
const bool savedProperties = SavePropertiesToSourceData(m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property)
|
||||
{
|
||||
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue);
|
||||
});
|
||||
|
||||
@@ -304,18 +299,13 @@ namespace MaterialEditor
|
||||
|
||||
// create source data from properties
|
||||
MaterialSourceData sourceData;
|
||||
sourceData.m_materialType = m_materialSourceData.m_materialType;
|
||||
sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial;
|
||||
|
||||
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
|
||||
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
|
||||
|
||||
// Force save data to store forward slashes
|
||||
AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/");
|
||||
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
|
||||
sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType);
|
||||
sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial);
|
||||
|
||||
// populate sourceData with modified or overwritten properties
|
||||
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) {
|
||||
const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property)
|
||||
{
|
||||
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue);
|
||||
});
|
||||
|
||||
@@ -377,23 +367,18 @@ namespace MaterialEditor
|
||||
|
||||
// create source data from properties
|
||||
MaterialSourceData sourceData;
|
||||
sourceData.m_materialType = m_materialSourceData.m_materialType;
|
||||
|
||||
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
|
||||
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
|
||||
sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType);
|
||||
|
||||
// Only assign a parent path if the source was a .material
|
||||
if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension))
|
||||
{
|
||||
sourceData.m_parentMaterial = m_relativePath;
|
||||
sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_absolutePath);
|
||||
}
|
||||
|
||||
// Force save data to store forward slashes
|
||||
AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/");
|
||||
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
|
||||
|
||||
// populate sourceData with modified properties
|
||||
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) {
|
||||
const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property)
|
||||
{
|
||||
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue);
|
||||
});
|
||||
|
||||
@@ -590,7 +575,8 @@ namespace MaterialEditor
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialDocument::SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const
|
||||
bool MaterialDocument::SavePropertiesToSourceData(
|
||||
const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace RPI;
|
||||
@@ -598,7 +584,7 @@ namespace MaterialEditor
|
||||
bool result = true;
|
||||
|
||||
// populate sourceData with properties that meet the filter
|
||||
m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) {
|
||||
m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) {
|
||||
|
||||
const MaterialPropertyId propertyId(groupName, propertyName);
|
||||
|
||||
@@ -608,7 +594,7 @@ namespace MaterialEditor
|
||||
MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue());
|
||||
if (propertyValue.IsValid())
|
||||
{
|
||||
if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue))
|
||||
if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyDefinition, propertyValue))
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str());
|
||||
result = false;
|
||||
@@ -662,8 +648,6 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string materialTypeSourceFilePath;
|
||||
|
||||
// The material document and inspector are constructed from source data
|
||||
if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension))
|
||||
{
|
||||
@@ -674,13 +658,24 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must also always load the material type data for a complete, ordered set of the
|
||||
// groups and properties that will be needed for comparison and building the inspector
|
||||
materialTypeSourceFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType);
|
||||
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath);
|
||||
// We always need the absolute path for the material type and parent material to load source data and resolving
|
||||
// relative paths when saving. This will convert and store them as absolute paths for use within the document.
|
||||
if (!m_materialSourceData.m_parentMaterial.empty())
|
||||
{
|
||||
m_materialSourceData.m_parentMaterial =
|
||||
AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial);
|
||||
}
|
||||
|
||||
if (!m_materialSourceData.m_materialType.empty())
|
||||
{
|
||||
m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType);
|
||||
}
|
||||
|
||||
// Load the material type source data which provides the layout and default values of all of the properties
|
||||
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType);
|
||||
if (!materialTypeOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str());
|
||||
return false;
|
||||
}
|
||||
m_materialTypeSourceData = materialTypeOutcome.GetValue();
|
||||
@@ -693,10 +688,10 @@ namespace MaterialEditor
|
||||
}
|
||||
else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension))
|
||||
{
|
||||
materialTypeSourceFilePath = m_absolutePath;
|
||||
|
||||
// Load the material type source data, which will be used for enumerating properties and building material source data
|
||||
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath);
|
||||
// A material document can be created or loaded from material or material type source data. If we are attempting to load
|
||||
// material type source data then the material source data object can be created just by referencing the document path as the
|
||||
// material type path.
|
||||
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath);
|
||||
if (!materialTypeOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str());
|
||||
@@ -704,9 +699,8 @@ namespace MaterialEditor
|
||||
}
|
||||
m_materialTypeSourceData = materialTypeOutcome.GetValue();
|
||||
|
||||
// The document represents a material, not a material type.
|
||||
// If the input data is a material type file we have to generate the material source data by referencing it.
|
||||
m_materialSourceData.m_materialType = m_relativePath;
|
||||
// We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times.
|
||||
m_materialSourceData.m_materialType = m_absolutePath;
|
||||
m_materialSourceData.m_parentMaterial.clear();
|
||||
}
|
||||
else
|
||||
@@ -748,25 +742,24 @@ namespace MaterialEditor
|
||||
if (!m_materialSourceData.m_parentMaterial.empty())
|
||||
{
|
||||
AZ::RPI::MaterialSourceData parentMaterialSourceData;
|
||||
const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial);
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData))
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_materialSourceData.m_parentMaterial, parentMaterialSourceData))
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", m_materialSourceData.m_parentMaterial.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0);
|
||||
const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(m_materialSourceData.m_parentMaterial, 0);
|
||||
if (!parentMaterialAssetIdResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", m_materialSourceData.m_parentMaterial.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData(
|
||||
parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true);
|
||||
parentMaterialAssetIdResult.GetValue(), m_materialSourceData.m_parentMaterial, true, true);
|
||||
if (!parentMaterialAssetResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", m_materialSourceData.m_parentMaterial.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -877,7 +870,8 @@ namespace MaterialEditor
|
||||
m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig);
|
||||
}
|
||||
|
||||
const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout());
|
||||
const MaterialFunctorSourceData::EditorContext editorContext =
|
||||
MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout());
|
||||
for (Ptr<MaterialFunctorSourceDataHolder> functorData : m_materialTypeSourceData.m_materialFunctorSourceData)
|
||||
{
|
||||
MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext);
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace MaterialEditor
|
||||
void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const;
|
||||
bool SavePropertiesToSourceData(
|
||||
const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const;
|
||||
|
||||
bool OpenInternal(AZStd::string_view loadPath);
|
||||
|
||||
|
||||
@@ -27,6 +27,27 @@ ly_add_target(
|
||||
3rdParty::libpng
|
||||
)
|
||||
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
|
||||
ly_add_target(
|
||||
NAME Atom_Utils.TestUtils.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
atom_utils_editor_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AtomCore
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
AZ::AzToolsFramework
|
||||
)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
################################################################################
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Common/AssetSystemStub.h>
|
||||
#include <Atom/Utils/TestUtils/AssetSystemStub.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
namespace UnitTest
|
||||
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Include/Atom/Utils/TestUtils/AssetSystemStub.h
|
||||
Source/TestUtils/AssetSystemStub.cpp
|
||||
)
|
||||
+15
-37
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
@@ -97,51 +98,28 @@ namespace AZ
|
||||
|
||||
bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData)
|
||||
{
|
||||
// Construct the material source data object that will be exported
|
||||
AZ::RPI::MaterialSourceData exportData;
|
||||
|
||||
// Converting absolute material paths to relative paths
|
||||
bool result = false;
|
||||
AZ::Data::AssetInfo info;
|
||||
AZStd::string watchFolder;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
||||
editData.m_materialTypeSourcePath.c_str(), info, watchFolder);
|
||||
if (!result)
|
||||
if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() ||
|
||||
editData.m_materialTypeSourcePath.empty())
|
||||
{
|
||||
AZ_Error(
|
||||
"AZ::Render::EditorMaterialComponentUtil", false,
|
||||
"Failed to get material type source file info while attempting to export: %s", path.c_str());
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
exportData.m_materialType = info.m_relativePath;
|
||||
|
||||
if (!editData.m_materialParentSourcePath.empty())
|
||||
{
|
||||
result = false;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
||||
editData.m_materialParentSourcePath.c_str(), info, watchFolder);
|
||||
if (!result)
|
||||
{
|
||||
AZ_Error(
|
||||
"AZ::Render::EditorMaterialComponentUtil", false,
|
||||
"Failed to get parent material source file info while attempting to export: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
exportData.m_parentMaterial = info.m_relativePath;
|
||||
}
|
||||
// Construct the material source data object that will be exported
|
||||
AZ::RPI::MaterialSourceData exportData;
|
||||
exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion();
|
||||
exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath);
|
||||
exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath);
|
||||
|
||||
// Copy all of the properties from the material asset to the source data that will be exported
|
||||
result = true;
|
||||
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) {
|
||||
bool result = true;
|
||||
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){
|
||||
const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName);
|
||||
const AZ::RPI::MaterialPropertyIndex propertyIndex =
|
||||
editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName());
|
||||
|
||||
AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
|
||||
AZ::RPI::MaterialPropertyValue propertyValue =
|
||||
editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
|
||||
|
||||
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value;
|
||||
if (editData.m_materialParentAsset.IsReady())
|
||||
@@ -151,12 +129,12 @@ namespace AZ
|
||||
|
||||
// Check for and apply any property overrides before saving property values
|
||||
auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName());
|
||||
if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
|
||||
if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
|
||||
{
|
||||
propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second);
|
||||
}
|
||||
|
||||
if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue))
|
||||
if (!AtomToolsFramework::ConvertToExportFormat(path, propertyDefinition, propertyValue))
|
||||
{
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str());
|
||||
result = false;
|
||||
|
||||
+50
-22
@@ -9,8 +9,8 @@
|
||||
#include "SlideAlongAxisBasedOnAngle.h"
|
||||
#include "StartingPointCamera/StartingPointCameraUtilities.h"
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
namespace Camera
|
||||
{
|
||||
@@ -32,31 +32,43 @@ namespace Camera
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<SlideAlongAxisBasedOnAngle>("SlideAlongAxisBasedOnAngle", "Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along", "The Axis to slide along")
|
||||
->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards")
|
||||
->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left")
|
||||
->EnumAttribute(RelativeAxisType::UpDown, "Up and Down")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type", "The angle type to base the slide off of")
|
||||
->EnumAttribute(EulerAngleType::Pitch, "Pitch")
|
||||
->EnumAttribute(EulerAngleType::Roll, "Roll")
|
||||
->EnumAttribute(EulerAngleType::Yaw, "Yaw")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", "The maximum distance to slide in the positive")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, "m")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", "The maximum distance to slide in the negative")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, "m")
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.")
|
||||
editContext->Class<SlideAlongAxisBasedOnAngle>("SlideAlongAxisBasedOnAngle",
|
||||
"Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along",
|
||||
"The Axis to slide along")
|
||||
->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards")
|
||||
->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left")
|
||||
->EnumAttribute(RelativeAxisType::UpDown, "Up and Down")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type",
|
||||
"The angle type to base the slide off of")
|
||||
->EnumAttribute(EulerAngleType::Pitch, "Pitch")
|
||||
->EnumAttribute(EulerAngleType::Roll, "Roll")
|
||||
->EnumAttribute(EulerAngleType::Yaw, "Yaw")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance",
|
||||
"The maximum distance to slide in the positive")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, "m")
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance",
|
||||
"The maximum distance to slide in the negative")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, "m")
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::YAndZIgnored)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndZIgnored)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
|
||||
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndYIgnored)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget([[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform)
|
||||
void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget(
|
||||
[[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform)
|
||||
{
|
||||
float angle = GetEulerAngleFromTransform(outLookAtTargetTransform, m_angleTypeToChangeFor);
|
||||
float currentPositionOnRange = -angle / AZ::Constants::HalfPi;
|
||||
@@ -67,4 +79,20 @@ namespace Camera
|
||||
|
||||
outLookAtTargetTransform.SetTranslation(outLookAtTargetTransform.GetTranslation() + basis * currentPositionOnRange * slideScale);
|
||||
}
|
||||
}
|
||||
|
||||
bool SlideAlongAxisBasedOnAngle::XAndYIgnored() const
|
||||
{
|
||||
return m_ignoreX && m_ignoreY;
|
||||
}
|
||||
|
||||
bool SlideAlongAxisBasedOnAngle::XAndZIgnored() const
|
||||
{
|
||||
return m_ignoreX && m_ignoreZ;
|
||||
}
|
||||
|
||||
bool SlideAlongAxisBasedOnAngle::YAndZIgnored() const
|
||||
{
|
||||
return m_ignoreY && m_ignoreZ;
|
||||
}
|
||||
|
||||
} // namespace Camera
|
||||
|
||||
+7
-3
@@ -6,11 +6,11 @@
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include <CameraFramework/ICameraLookAtBehavior.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include "StartingPointCamera/StartingPointCameraConstants.h"
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <CameraFramework/ICameraLookAtBehavior.h>
|
||||
|
||||
namespace Camera
|
||||
{
|
||||
@@ -38,6 +38,10 @@ namespace Camera
|
||||
void Activate(AZ::EntityId) override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
bool XAndYIgnored() const;
|
||||
bool XAndZIgnored() const;
|
||||
bool YAndZIgnored() const;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reflected data
|
||||
|
||||
Reference in New Issue
Block a user