MaterialHotReloadTestComponent.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <MaterialHotReloadTestComponent.h>
  9. #include <SampleComponentManager.h>
  10. #include <SampleComponentConfig.h>
  11. #include <Automation/ScriptableImGui.h>
  12. #include <Automation/ScriptRunnerBus.h>
  13. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  14. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  15. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  16. #include <Atom/Feature/Material/MaterialAssignment.h>
  17. #include <AzCore/IO/Path/Path.h>
  18. #include <AzFramework/IO/LocalFileIO.h>
  19. #include <AzFramework/Asset/AssetSystemBus.h>
  20. #include <AzFramework/Asset/AssetProcessorMessages.h>
  21. #include <Atom/RPI.Public/RPISystemInterface.h>
  22. #include <AzCore/Utils/Utils.h>
  23. #include <RHI/BasicRHIComponent.h>
  24. namespace AtomSampleViewer
  25. {
  26. using namespace AZ;
  27. using namespace RPI;
  28. namespace
  29. {
  30. namespace Sources
  31. {
  32. static constexpr const char MaterialFileName[] = "HotReloadTest.material";
  33. static constexpr const char MaterialTypeFileName[] = "HotReloadTest.materialtype";
  34. static constexpr const char ShaderFileName[] = "HotReloadTest.shader";
  35. static constexpr const char AzslFileName[] = "HotReloadTest.azsl";
  36. static constexpr const char ShaderVariantListFileName[] = "HotReloadTest.shadervariantlist";
  37. }
  38. namespace Products
  39. {
  40. static constexpr const char ModelFilePath[] = "objects/plane.azmodel";
  41. static constexpr const char MaterialFilePath[] = "materials/hotreloadtest/temp/hotreloadtest.azmaterial";
  42. static constexpr const char MaterialTypeFilePath[] = "materials/hotreloadtest/temp/hotreloadtest.azmaterialtype";
  43. static constexpr const char ShaderFilePath[] = "materials/hotreloadtest/temp/hotreloadtest.azshader";
  44. static constexpr const char ShaderVariantTreeFileName[] = "hotreloadtest.azshadervarianttree";
  45. static AZStd::string GetShaderVariantFileName(RPI::ShaderVariantStableId stableId)
  46. {
  47. RPISystemInterface* rpiSystem = RPISystemInterface::Get();
  48. Name apiName = rpiSystem->GetRenderApiName();
  49. AZStd::string filePath = AZStd::string::format("hotreloadtest_%s_%u.azshadervariant", apiName.GetCStr(), stableId.GetIndex());
  50. return filePath;
  51. }
  52. // These materials are used to communicate which shader variant is being used, for screenshot comparison tests.
  53. static constexpr const char RootVariantIndicatorMaterialFilePath[] = "materials/hotreloadtest/testdata/variantselection_root.azmaterial";
  54. static constexpr const char FullyBakedVariantIndicatorMaterialFilePath[] = "materials/hotreloadtest/testdata/variantselection_fullybaked.azmaterial";
  55. }
  56. namespace TestData
  57. {
  58. namespace MaterialFileNames
  59. {
  60. static constexpr const char Default[] = "Material_UseDefaults.txt";
  61. static constexpr const char ChangePrimaryToRed[] = "Material_ChangePrimaryToRed.txt";
  62. static constexpr const char ChangePrimaryToBlue[] = "Material_ChangePrimaryToBlue.txt";
  63. }
  64. namespace MaterialTypeFileNames
  65. {
  66. static constexpr const char StraightLines[] = "MaterialType_StraightLines.txt";
  67. static constexpr const char WavyLines[] = "MaterialType_WavyLines.txt";
  68. }
  69. namespace ShaderFileNames
  70. {
  71. static constexpr const char BlendingOff[] = "Shader_BlendingOff.txt";
  72. static constexpr const char BlendingOn[] = "Shader_BlendingOn.txt";
  73. }
  74. namespace AzslFileNames
  75. {
  76. static constexpr const char HorizontalPattern[] = "AZSL_HorizontalPattern.txt";
  77. static constexpr const char VerticalPattern[] = "AZSL_VerticalPattern.txt";
  78. }
  79. namespace ShaderVariantListFileNames
  80. {
  81. static constexpr const char All[] = "ShaderVariantList_All.txt";
  82. static constexpr const char OnlyStraightLines[] = "ShaderVariantList_OnlyStraightLines.txt";
  83. static constexpr const char OnlyWavyLines[] = "ShaderVariantList_OnlyWavyLines.txt";
  84. }
  85. }
  86. }
  87. void MaterialHotReloadTestComponent::Reflect(ReflectContext* context)
  88. {
  89. if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
  90. {
  91. serializeContext->Class<MaterialHotReloadTestComponent, CommonSampleComponentBase>()
  92. ->Version(0)
  93. ;
  94. }
  95. }
  96. MaterialHotReloadTestComponent::MaterialHotReloadTestComponent()
  97. : m_imguiSidebar{"@user@/MaterialHotReloadTestComponent/sidebar.xml"}
  98. {
  99. }
  100. void MaterialHotReloadTestComponent::InitTestDataFolders()
  101. {
  102. auto io = AZ::IO::LocalFileIO::GetInstance();
  103. auto projectPath = AZ::Utils::GetProjectPath();
  104. AZStd::string mainTestFolder;
  105. AzFramework::StringFunc::Path::Join(projectPath.c_str(), "Materials/HotReloadTest/", mainTestFolder);
  106. AzFramework::StringFunc::Path::Join(mainTestFolder.c_str(), "TestData/", m_testDataFolder);
  107. if (!io->Exists(m_testDataFolder.c_str()))
  108. {
  109. AZ_Error("MaterialHotReloadTestComponent", false, "Could not find source folder '%s'. This sample can only be used on dev platforms.", m_testDataFolder.c_str());
  110. m_testDataFolder.clear();
  111. return;
  112. }
  113. AzFramework::StringFunc::Path::Join(mainTestFolder.c_str(), "Temp/", m_tempSourceFolder);
  114. if (!io->CreatePath(m_tempSourceFolder.c_str()))
  115. {
  116. AZ_Error("MaterialHotReloadTestComponent", false, "Could not create temp folder '%s'.", m_tempSourceFolder.c_str());
  117. }
  118. }
  119. void MaterialHotReloadTestComponent::Activate()
  120. {
  121. m_initStatus = InitStatus::None;
  122. TickBus::Handler::BusConnect();
  123. m_imguiSidebar.Activate();
  124. InitTestDataFolders();
  125. // Delete any existing temp files and wait for the assets to disappear, to ensure we have a clean slate.
  126. // (If we were to just replace existing temp source files with the default ones without fully
  127. // removing them first, it would be tricky to figure out whether the assets loaded assets are the new
  128. // ones or stale ones left over from a prior instance of this sample).
  129. DeleteTestFile(Sources::MaterialFileName);
  130. DeleteTestFile(Sources::MaterialTypeFileName);
  131. DeleteTestFile(Sources::ShaderFileName);
  132. DeleteTestFile(Sources::AzslFileName);
  133. DeleteTestFile(Sources::ShaderVariantListFileName);
  134. m_initStatus = InitStatus::ClearingTestAssets;
  135. m_clearAssetsTimeout = 5.0f;
  136. // Wait until the test material is fully initialized. Use a long timeout because it can take a while for the shaders to compile.
  137. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, LongTimeout);
  138. Data::AssetId modelAssetId;
  139. Data::AssetCatalogRequestBus::BroadcastResult(modelAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, Products::ModelFilePath, nullptr, false);
  140. AZ_Assert(modelAssetId.IsValid(), "Failed to get model asset id: %s", Products::ModelFilePath);
  141. m_modelAsset.Create(modelAssetId);
  142. const Transform cameraTransform = Transform::CreateFromQuaternionAndTranslation(
  143. Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), AZ::Constants::Pi),
  144. Vector3{0.0f, 2.0f, 0.0f}
  145. );
  146. AZ::TransformBus::Event(GetCameraEntityId(), &AZ::TransformBus::Events::SetWorldTM, cameraTransform);
  147. m_meshFeatureProcessor = Scene::GetFeatureProcessorForEntityContextId<Render::MeshFeatureProcessorInterface>(GetEntityContextId());
  148. // The shader variant indicator banner will appear right below the main test mesh
  149. m_shaderVariantIndicatorMeshTransform = Transform::CreateIdentity();
  150. m_shaderVariantIndicatorMeshTransform.SetTranslation(Vector3{0.0f, 0.0f, -0.6f});
  151. m_shaderVariantIndicatorMeshNonUniformScale = Vector3(1.0f, 0.125f, 1.0f);
  152. m_shaderVariantIndicatorMeshTransform.SetRotation(Quaternion::CreateFromAxisAngle(Vector3::CreateAxisX(), -AZ::Constants::HalfPi));
  153. // Load materials that will be used to indicate which shader variant is active...
  154. Data::Asset<MaterialAsset> indicatorMaterialAsset;
  155. indicatorMaterialAsset = AssetUtils::LoadAssetByProductPath<MaterialAsset>(Products::RootVariantIndicatorMaterialFilePath, AssetUtils::TraceLevel::Assert);
  156. m_shaderVariantIndicatorMaterial_root = Material::FindOrCreate(indicatorMaterialAsset);
  157. indicatorMaterialAsset = AssetUtils::LoadAssetByProductPath<MaterialAsset>(Products::FullyBakedVariantIndicatorMaterialFilePath, AssetUtils::TraceLevel::Assert);
  158. m_shaderVariantIndicatorMaterial_fullyBaked = Material::FindOrCreate(indicatorMaterialAsset);
  159. }
  160. void MaterialHotReloadTestComponent::Deactivate()
  161. {
  162. m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
  163. m_meshFeatureProcessor->ReleaseMesh(m_shaderVariantIndicatorMeshHandle);
  164. m_shaderVariantIndicatorMaterial_root.reset();
  165. m_shaderVariantIndicatorMaterial_fullyBaked.reset();
  166. m_shaderVariantIndicatorMaterial_current.reset();
  167. Data::AssetBus::Handler::BusDisconnect();
  168. TickBus::Handler::BusDisconnect();
  169. m_imguiSidebar.Deactivate();
  170. m_initStatus = InitStatus::None;
  171. }
  172. void MaterialHotReloadTestComponent::DeleteTestFile(const char* tempSourceFile)
  173. {
  174. AZ::IO::Path deletePath = AZ::IO::Path(m_tempSourceFolder).Append(tempSourceFile);
  175. if (AZ::IO::LocalFileIO::GetInstance()->Exists(deletePath.c_str()))
  176. {
  177. if (!AZ::IO::LocalFileIO::GetInstance()->Remove(deletePath.c_str()))
  178. {
  179. AZ_Error("MaterialHotReloadTestComponent", false, "Failed to delete '%s'.", deletePath.c_str());
  180. }
  181. }
  182. }
  183. void MaterialHotReloadTestComponent::CopyTestFile(const AZStd::string& testDataFile, const AZStd::string& tempSourceFile)
  184. {
  185. // Instead of copying the file using AZ::IO::LocalFileIO, we load the file and write out a new file over top
  186. // the destination. This is necessary to make the AP reliably detect the changes (if we just copy the file,
  187. // sometimes it recognizes the OS level copy as an updated file and sometimes not).
  188. AZ::IO::Path copyFrom = AZ::IO::Path(m_testDataFolder).Append(testDataFile);
  189. AZ::IO::Path copyTo = AZ::IO::Path(m_tempSourceFolder).Append(tempSourceFile);
  190. auto readResult = AZ::Utils::ReadFile(copyFrom.c_str());
  191. if (!readResult.IsSuccess())
  192. {
  193. AZ_Error("MaterialHotReloadTestComponent", false, "%s", readResult.GetError().c_str());
  194. return;
  195. }
  196. auto writeResult = AZ::Utils::WriteFile(readResult.GetValue(), copyTo.c_str());
  197. if (!writeResult.IsSuccess())
  198. {
  199. AZ_Error("MaterialHotReloadTestComponent", false, "%s", writeResult.GetError().c_str());
  200. return;
  201. }
  202. }
  203. const char* ToString(AzFramework::AssetSystem::AssetStatus status)
  204. {
  205. switch (status)
  206. {
  207. case AzFramework::AssetSystem::AssetStatus_Missing: return "Missing";
  208. case AzFramework::AssetSystem::AssetStatus_Queued: return "Queued...";
  209. case AzFramework::AssetSystem::AssetStatus_Compiling: return "Compiling...";
  210. case AzFramework::AssetSystem::AssetStatus_Compiled: return "Compiled";
  211. case AzFramework::AssetSystem::AssetStatus_Failed: return "Failed";
  212. default: return "Unknown";
  213. }
  214. }
  215. AzFramework::AssetSystem::AssetStatus MaterialHotReloadTestComponent::GetTestAssetStatus(const char* tempSourceFile) const
  216. {
  217. AZStd::string filePath = AZStd::string("materials/hotreloadtest/temp/") + tempSourceFile;
  218. AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus::AssetStatus_Unknown;
  219. AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusSearchType,
  220. filePath.c_str(), AzFramework::AssetSystem::RequestAssetStatus::SearchType::Exact);
  221. return status;
  222. }
  223. void MaterialHotReloadTestComponent::DrawAssetStatus(const char* tempSourceFile, bool includeFileName)
  224. {
  225. AzFramework::AssetSystem::AssetStatus status = GetTestAssetStatus(tempSourceFile);
  226. if (includeFileName)
  227. {
  228. ImGui::Text("%s", tempSourceFile);
  229. ImGui::Indent();
  230. }
  231. ImGui::Text("Status:");
  232. ImGui::SameLine();
  233. ImGui::Text("%s", ToString(status));
  234. if (includeFileName)
  235. {
  236. ImGui::Unindent();
  237. }
  238. }
  239. Data::AssetId MaterialHotReloadTestComponent::GetAssetId(const char* productFilePath)
  240. {
  241. Data::AssetId assetId;
  242. Data::AssetCatalogRequestBus::BroadcastResult(assetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, productFilePath, nullptr, false);
  243. return assetId;
  244. }
  245. void MaterialHotReloadTestComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  246. {
  247. if (m_initStatus == InitStatus::WaitingForDefaultMaterialToLoad && asset.GetId() == m_materialAsset.GetId())
  248. {
  249. m_materialAsset = asset;
  250. Data::AssetBus::Handler::BusDisconnect(asset.GetId());
  251. m_initStatus = InitStatus::Ready;
  252. // Now that we finally have the material asset, we can add the model to the scene...
  253. m_material = Material::Create(m_materialAsset);
  254. Transform meshTransform = Transform::CreateFromQuaternion(Quaternion::CreateFromAxisAngle(Vector3::CreateAxisX(), -AZ::Constants::HalfPi));
  255. m_meshHandle = m_meshFeatureProcessor->AcquireMesh(AZ::Render::MeshHandleDescriptor{ m_modelAsset }, m_material);
  256. m_meshFeatureProcessor->SetTransform(m_meshHandle, meshTransform);
  257. Data::Instance<RPI::Model> model = GetMeshFeatureProcessor()->GetModel(m_meshHandle);
  258. if (model)
  259. {
  260. // Both the model and material are ready so scripts can continue
  261. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  262. }
  263. else
  264. {
  265. // The material is ready but the model isn't ready yet; wait until it's ready before allowing scripts to continue
  266. m_meshChangedHandler = AZ::Render::MeshFeatureProcessorInterface::ModelChangedEvent::Handler
  267. {
  268. [](AZ::Data::Instance<AZ::RPI::Model> model) { ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript); }
  269. };
  270. GetMeshFeatureProcessor()->ConnectModelChangeEventHandler(m_meshHandle, m_meshChangedHandler);
  271. }
  272. }
  273. }
  274. MaterialHotReloadTestComponent::ShaderVariantStatus MaterialHotReloadTestComponent::GetShaderVariantStatus() const
  275. {
  276. ShaderVariantStatus shaderVariantStatus = ShaderVariantStatus::None;
  277. if (m_material)
  278. {
  279. const ShaderVariantId variantId = m_material->GetShaderCollection()[0].GetShaderVariantId();
  280. auto searchResult = m_material->GetShaderCollection()[0].GetShaderAsset()->FindVariantStableId(variantId);
  281. if (searchResult.IsFullyBaked())
  282. {
  283. shaderVariantStatus = ShaderVariantStatus::FullyBaked;
  284. }
  285. else if (searchResult.IsRoot())
  286. {
  287. shaderVariantStatus = ShaderVariantStatus::Root;
  288. }
  289. else
  290. {
  291. shaderVariantStatus = ShaderVariantStatus::PartiallyBaked;
  292. }
  293. }
  294. return shaderVariantStatus;
  295. }
  296. void MaterialHotReloadTestComponent::OnTick([[maybe_unused]] float deltaTime, ScriptTimePoint /*scriptTime*/)
  297. {
  298. if (m_initStatus == InitStatus::ClearingTestAssets)
  299. {
  300. m_clearAssetsTimeout -= deltaTime;
  301. Data::AssetId materialAssetId = GetAssetId(Products::MaterialFilePath);
  302. Data::AssetId materialTypeAssetId = GetAssetId(Products::MaterialTypeFilePath);
  303. Data::AssetId shaderAssetId = GetAssetId(Products::ShaderFilePath);
  304. bool proceed = !materialAssetId.IsValid() && !materialTypeAssetId.IsValid() && !shaderAssetId.IsValid();
  305. if (!proceed && m_clearAssetsTimeout < 0)
  306. {
  307. // There was a specific bug in the Asset Processor where deleting a source file does not always remove the corresponding product
  308. // from the cache and from the asset database.
  309. AZ_Error("MaterialHotReloadTestComponent", false, "Timed out while waiting for test assets to be removed.");
  310. proceed = true;
  311. }
  312. if (proceed)
  313. {
  314. // [GFX TODO] [ATOM-5899] Once this ticket is addressed, This block can call all required CopyTestFile() at once,
  315. // and the states InitStatus::CopyingDefault***TestFile won't be needed.
  316. // Any stale assets have been cleared, now we can create the new ones.
  317. // Copy a default set files into the temp folder.
  318. CopyTestFile(TestData::AzslFileNames::HorizontalPattern, Sources::AzslFileName);
  319. CopyTestFile(TestData::ShaderFileNames::BlendingOff, Sources::ShaderFileName);
  320. m_initStatus = InitStatus::CopyingDefaultShaderTestFile;
  321. }
  322. }
  323. if (m_initStatus == InitStatus::CopyingDefaultShaderTestFile)
  324. {
  325. AzFramework::AssetSystem::AssetStatus status = GetTestAssetStatus(Sources::ShaderFileName);
  326. if (status == AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiled)
  327. {
  328. CopyTestFile(TestData::MaterialTypeFileNames::StraightLines, Sources::MaterialTypeFileName);
  329. m_initStatus = InitStatus::CopyingDefaultMaterialTypeTestFile;
  330. }
  331. }
  332. else if (m_initStatus == InitStatus::CopyingDefaultMaterialTypeTestFile)
  333. {
  334. AzFramework::AssetSystem::AssetStatus status = GetTestAssetStatus(Sources::MaterialTypeFileName);
  335. if (status == AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiled)
  336. {
  337. CopyTestFile(TestData::MaterialFileNames::Default, Sources::MaterialFileName);
  338. m_initStatus = InitStatus::WaitingForDefaultMaterialToRegister;
  339. }
  340. }
  341. if (m_initStatus == InitStatus::WaitingForDefaultMaterialToRegister)
  342. {
  343. Data::AssetId materialAssetId = GetAssetId(Products::MaterialFilePath);
  344. if (materialAssetId.IsValid())
  345. {
  346. m_initStatus = InitStatus::WaitingForDefaultMaterialToLoad;
  347. Data::AssetBus::Handler::BusConnect(materialAssetId);
  348. m_materialAsset.Create(materialAssetId, true);
  349. }
  350. }
  351. auto shaderVariantStatus = GetShaderVariantStatus();
  352. if (shaderVariantStatus == ShaderVariantStatus::None)
  353. {
  354. m_meshFeatureProcessor->ReleaseMesh(m_shaderVariantIndicatorMeshHandle);
  355. m_shaderVariantIndicatorMaterial_current.reset();
  356. }
  357. else
  358. {
  359. bool updateIndicatorMesh = false;
  360. if (shaderVariantStatus == ShaderVariantStatus::Root)
  361. {
  362. if (m_shaderVariantIndicatorMaterial_current != m_shaderVariantIndicatorMaterial_root)
  363. {
  364. m_shaderVariantIndicatorMaterial_current = m_shaderVariantIndicatorMaterial_root;
  365. updateIndicatorMesh = true;
  366. }
  367. }
  368. else if(shaderVariantStatus == ShaderVariantStatus::FullyBaked)
  369. {
  370. if (m_shaderVariantIndicatorMaterial_current != m_shaderVariantIndicatorMaterial_fullyBaked)
  371. {
  372. m_shaderVariantIndicatorMaterial_current = m_shaderVariantIndicatorMaterial_fullyBaked;
  373. updateIndicatorMesh = true;
  374. }
  375. }
  376. else
  377. {
  378. AZ_Assert(false, "Unsupported ShaderVariantStatus");
  379. }
  380. if (updateIndicatorMesh)
  381. {
  382. m_meshFeatureProcessor->ReleaseMesh(m_shaderVariantIndicatorMeshHandle);
  383. m_shaderVariantIndicatorMeshHandle = m_meshFeatureProcessor->AcquireMesh(Render::MeshHandleDescriptor{ m_modelAsset }, m_shaderVariantIndicatorMaterial_current);
  384. m_meshFeatureProcessor->SetTransform(m_shaderVariantIndicatorMeshHandle, m_shaderVariantIndicatorMeshTransform,
  385. m_shaderVariantIndicatorMeshNonUniformScale);
  386. }
  387. }
  388. if (m_imguiSidebar.Begin())
  389. {
  390. if (m_initStatus != InitStatus::Ready)
  391. {
  392. ImGui::Text("Waiting for assets...");
  393. ImGui::Separator();
  394. }
  395. ImGui::Text(Sources::MaterialFileName);
  396. ImGui::Indent();
  397. {
  398. DrawAssetStatus(Sources::MaterialFileName);
  399. if (m_initStatus == InitStatus::Ready)
  400. {
  401. if (ScriptableImGui::Button("Default Colors"))
  402. {
  403. CopyTestFile(TestData::MaterialFileNames::Default, Sources::MaterialFileName);
  404. }
  405. if (ScriptableImGui::Button("ColorA = Red"))
  406. {
  407. CopyTestFile(TestData::MaterialFileNames::ChangePrimaryToRed, Sources::MaterialFileName);
  408. }
  409. if (ScriptableImGui::Button("ColorA = Blue"))
  410. {
  411. CopyTestFile(TestData::MaterialFileNames::ChangePrimaryToBlue, Sources::MaterialFileName);
  412. }
  413. }
  414. }
  415. ImGui::Unindent();
  416. ImGui::Text(Sources::MaterialTypeFileName);
  417. ImGui::Indent();
  418. {
  419. DrawAssetStatus(Sources::MaterialTypeFileName);
  420. if (m_initStatus == InitStatus::Ready)
  421. {
  422. if (ScriptableImGui::Button("Straight Lines"))
  423. {
  424. CopyTestFile(TestData::MaterialTypeFileNames::StraightLines, Sources::MaterialTypeFileName);
  425. }
  426. if (ScriptableImGui::Button("Wavy Lines"))
  427. {
  428. CopyTestFile(TestData::MaterialTypeFileNames::WavyLines, Sources::MaterialTypeFileName);
  429. }
  430. }
  431. }
  432. ImGui::Unindent();
  433. ImGui::Text(Sources::ShaderFileName);
  434. ImGui::Indent();
  435. {
  436. DrawAssetStatus(Sources::ShaderFileName);
  437. if (m_initStatus == InitStatus::Ready)
  438. {
  439. if (ScriptableImGui::Button("Blending Off"))
  440. {
  441. CopyTestFile(TestData::ShaderFileNames::BlendingOff, Sources::ShaderFileName);
  442. }
  443. if (ScriptableImGui::Button("Blending On"))
  444. {
  445. CopyTestFile(TestData::ShaderFileNames::BlendingOn, Sources::ShaderFileName);
  446. }
  447. }
  448. }
  449. ImGui::Unindent();
  450. ImGui::Text(Sources::AzslFileName);
  451. ImGui::Indent();
  452. {
  453. // The AZSL file is a source dependency of the .shader file, so display the same asset status
  454. DrawAssetStatus(Sources::AzslFileName);
  455. if (m_initStatus == InitStatus::Ready)
  456. {
  457. if (ScriptableImGui::Button("Horizontal Pattern"))
  458. {
  459. CopyTestFile(TestData::AzslFileNames::HorizontalPattern, Sources::AzslFileName);
  460. }
  461. if (ScriptableImGui::Button("Vertical Pattern"))
  462. {
  463. CopyTestFile(TestData::AzslFileNames::VerticalPattern, Sources::AzslFileName);
  464. }
  465. }
  466. }
  467. ImGui::Unindent();
  468. ImGui::Text(Sources::ShaderVariantListFileName);
  469. ImGui::Indent();
  470. {
  471. // The AZSL file is a source dependency of the .shader file, so display the same asset status
  472. DrawAssetStatus(Sources::ShaderVariantListFileName, false);
  473. DrawAssetStatus(Products::ShaderVariantTreeFileName, true);
  474. DrawAssetStatus(Products::GetShaderVariantFileName(ShaderVariantStableId{0}).c_str(), true);
  475. DrawAssetStatus(Products::GetShaderVariantFileName(ShaderVariantStableId{1}).c_str(), true);
  476. DrawAssetStatus(Products::GetShaderVariantFileName(ShaderVariantStableId{2}).c_str(), true);
  477. if (m_initStatus == InitStatus::Ready)
  478. {
  479. ScriptableImGui::PushNameContext("ShaderVariantList");
  480. if (ScriptableImGui::Button("None"))
  481. {
  482. DeleteTestFile(Sources::ShaderVariantListFileName);
  483. }
  484. if (ScriptableImGui::Button("All"))
  485. {
  486. CopyTestFile(TestData::ShaderVariantListFileNames::All, Sources::ShaderVariantListFileName);
  487. }
  488. if (ScriptableImGui::Button("Only Wavy Lines"))
  489. {
  490. CopyTestFile(TestData::ShaderVariantListFileNames::OnlyWavyLines, Sources::ShaderVariantListFileName);
  491. }
  492. if (ScriptableImGui::Button("Only Straight Lines"))
  493. {
  494. CopyTestFile(TestData::ShaderVariantListFileNames::OnlyStraightLines, Sources::ShaderVariantListFileName);
  495. }
  496. ScriptableImGui::PopNameContext();
  497. }
  498. }
  499. ImGui::Unindent();
  500. m_imguiSidebar.End();
  501. }
  502. }
  503. } // namespace AtomSampleViewer