MaterialHotReloadTestComponent.cpp 26 KB

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