DebugDrawSystemComponent.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  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 <AzCore/Serialization/SerializeContext.h>
  9. #include <AzCore/Serialization/EditContext.h>
  10. #include <AzCore/Component/TickBus.h>
  11. #include <AzCore/Component/TransformBus.h>
  12. #include <AzCore/RTTI/BehaviorContext.h>
  13. #include <AzCore/std/parallel/lock.h>
  14. #include "DebugDrawSystemComponent.h"
  15. // Editor specific
  16. #ifdef DEBUGDRAW_GEM_EDITOR
  17. #include "EditorDebugDrawComponentCommon.h" // for Reflection
  18. #include "EditorDebugDrawLineComponent.h"
  19. #include "EditorDebugDrawRayComponent.h"
  20. #include "EditorDebugDrawSphereComponent.h"
  21. #include "EditorDebugDrawObbComponent.h"
  22. #include "EditorDebugDrawTextComponent.h"
  23. #include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
  24. #endif // DEBUGDRAW_GEM_EDITOR
  25. #include <Atom/RPI.Public/RPISystemInterface.h>
  26. #include <Atom/RPI.Public/Scene.h>
  27. namespace DebugDraw
  28. {
  29. void DebugDrawSystemComponent::Reflect(AZ::ReflectContext* context)
  30. {
  31. #ifdef DEBUGDRAW_GEM_EDITOR
  32. EditorDebugDrawComponentSettings::Reflect(context);
  33. #endif // DEBUGDRAW_GEM_EDITOR
  34. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  35. {
  36. serialize->Class<DebugDrawSystemComponent, AZ::Component>()
  37. ->Version(0);
  38. if (AZ::EditContext* ec = serialize->GetEditContext())
  39. {
  40. ec->Class<DebugDrawSystemComponent>("DebugDraw", "Provides game runtime debug visualization.")
  41. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  42. ->Attribute(AZ::Edit::Attributes::Category, "Debugging")
  43. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  44. ;
  45. }
  46. }
  47. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  48. {
  49. behaviorContext->EBus<DebugDrawRequestBus>("DebugDrawRequestBus")
  50. ->Attribute(AZ::Script::Attributes::Category, "Debug")
  51. ->Event("DrawAabb", &DebugDrawRequestBus::Events::DrawAabb)
  52. ->Event("DrawAabbOnEntity", &DebugDrawRequestBus::Events::DrawAabbOnEntity)
  53. ->Event("DrawLineLocationToLocation", &DebugDrawRequestBus::Events::DrawLineLocationToLocation)
  54. ->Event("DrawLineEntityToLocation", &DebugDrawRequestBus::Events::DrawLineEntityToLocation)
  55. ->Event("DrawLineEntityToEntity", &DebugDrawRequestBus::Events::DrawLineEntityToEntity)
  56. ->Event("DrawObb", &DebugDrawRequestBus::Events::DrawObb)
  57. ->Event("DrawObbOnEntity", &DebugDrawRequestBus::Events::DrawObbOnEntity)
  58. ->Event("DrawRayLocationToDirection", &DebugDrawRequestBus::Events::DrawRayLocationToDirection)
  59. ->Event("DrawRayEntityToDirection", &DebugDrawRequestBus::Events::DrawRayEntityToDirection)
  60. ->Event("DrawRayEntityToEntity", &DebugDrawRequestBus::Events::DrawRayEntityToEntity)
  61. ->Event("DrawSphereAtLocation", &DebugDrawRequestBus::Events::DrawSphereAtLocation)
  62. ->Event("DrawSphereOnEntity", &DebugDrawRequestBus::Events::DrawSphereOnEntity)
  63. ->Event("DrawTextAtLocation", &DebugDrawRequestBus::Events::DrawTextAtLocation)
  64. ->Event("DrawTextOnEntity", &DebugDrawRequestBus::Events::DrawTextOnEntity)
  65. ->Event("DrawTextOnScreen", &DebugDrawRequestBus::Events::DrawTextOnScreen)
  66. ;
  67. }
  68. }
  69. void DebugDrawSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  70. {
  71. provided.push_back(AZ_CRC("DebugDrawService", 0x651d8874));
  72. }
  73. void DebugDrawSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  74. {
  75. incompatible.push_back(AZ_CRC("DebugDrawService", 0x651d8874));
  76. }
  77. void DebugDrawSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  78. {
  79. required.push_back(AZ_CRC("RPISystem", 0xf2add773));
  80. }
  81. void DebugDrawSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  82. {
  83. (void)dependent;
  84. }
  85. void DebugDrawSystemComponent::Init()
  86. {
  87. }
  88. void DebugDrawSystemComponent::Activate()
  89. {
  90. DebugDrawInternalRequestBus::Handler::BusConnect();
  91. DebugDrawRequestBus::Handler::BusConnect();
  92. AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
  93. #ifdef DEBUGDRAW_GEM_EDITOR
  94. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
  95. #endif // DEBUGDRAW_GEM_EDITOR
  96. }
  97. void DebugDrawSystemComponent::Deactivate()
  98. {
  99. #ifdef DEBUGDRAW_GEM_EDITOR
  100. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
  101. #endif // DEBUGDRAW_GEM_EDITOR
  102. AZ::RPI::SceneNotificationBus::Handler::BusDisconnect();
  103. DebugDrawRequestBus::Handler::BusDisconnect();
  104. DebugDrawInternalRequestBus::Handler::BusDisconnect();
  105. {
  106. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  107. m_activeAabbs.clear();
  108. }
  109. {
  110. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  111. m_activeLines.clear();
  112. }
  113. {
  114. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  115. m_activeObbs.clear();
  116. }
  117. {
  118. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  119. m_activeRays.clear();
  120. }
  121. {
  122. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  123. m_activeSpheres.clear();
  124. }
  125. {
  126. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  127. m_activeTexts.clear();
  128. }
  129. }
  130. void DebugDrawSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* scene)
  131. {
  132. AZ_Assert(scene, "Invalid scene received in OnBootstrapSceneReady");
  133. AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId());
  134. AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
  135. }
  136. #ifdef DEBUGDRAW_GEM_EDITOR
  137. void DebugDrawSystemComponent::OnStopPlayInEditor()
  138. {
  139. // Remove all debug elements that weren't triggered by editor components
  140. // We need this check because OnStopPlayInEditor() is called AFTER editor entities
  141. // have been re-activated, so at this time we have both our game AND editor
  142. // debug drawings active
  143. // Aabbs
  144. {
  145. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  146. AZStd::vector<DebugDrawAabbElement> elementsToSave;
  147. for (const DebugDrawAabbElement& element : m_activeAabbs)
  148. {
  149. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  150. {
  151. elementsToSave.push_back(element);
  152. }
  153. }
  154. m_activeAabbs.clear();
  155. m_activeAabbs.assign_rv(AZStd::forward<AZStd::vector<DebugDrawAabbElement>>(elementsToSave));
  156. }
  157. // Lines
  158. {
  159. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  160. AZStd::vector<DebugDrawLineElement> elementsToSave;
  161. for (const DebugDrawLineElement& element : m_activeLines)
  162. {
  163. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  164. {
  165. elementsToSave.push_back(element);
  166. }
  167. }
  168. m_activeLines.clear();
  169. m_activeLines.assign_rv(AZStd::forward<AZStd::vector<DebugDrawLineElement>>(elementsToSave));
  170. }
  171. // Obbs
  172. {
  173. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  174. AZStd::vector<DebugDrawObbElement> elementsToSave;
  175. for (const DebugDrawObbElement& element : m_activeObbs)
  176. {
  177. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  178. {
  179. elementsToSave.push_back(element);
  180. }
  181. }
  182. m_activeObbs.clear();
  183. m_activeObbs.assign_rv(AZStd::forward<AZStd::vector<DebugDrawObbElement>>(elementsToSave));
  184. }
  185. // Rays
  186. {
  187. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  188. AZStd::vector<DebugDrawRayElement> elementsToSave;
  189. for (const DebugDrawRayElement& element : m_activeRays)
  190. {
  191. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  192. {
  193. elementsToSave.push_back(element);
  194. }
  195. }
  196. m_activeRays.clear();
  197. m_activeRays.assign_rv(AZStd::forward<AZStd::vector<DebugDrawRayElement>>(elementsToSave));
  198. }
  199. // Spheres
  200. {
  201. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  202. AZStd::vector<DebugDrawSphereElement> elementsToSave;
  203. for (const DebugDrawSphereElement& element : m_activeSpheres)
  204. {
  205. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  206. {
  207. elementsToSave.push_back(element);
  208. }
  209. }
  210. m_activeSpheres.clear();
  211. m_activeSpheres.assign_rv(AZStd::forward<AZStd::vector<DebugDrawSphereElement>>(elementsToSave));
  212. }
  213. // Text
  214. {
  215. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  216. AZStd::vector<DebugDrawTextElement> elementsToSave;
  217. for (const DebugDrawTextElement& element : m_activeTexts)
  218. {
  219. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  220. {
  221. elementsToSave.push_back(element);
  222. }
  223. }
  224. m_activeTexts.clear();
  225. m_activeTexts.assign_rv(AZStd::forward<AZStd::vector<DebugDrawTextElement>>(elementsToSave));
  226. }
  227. }
  228. #endif // DEBUGDRAW_GEM_EDITOR
  229. void DebugDrawSystemComponent::OnBeginPrepareRender()
  230. {
  231. AZ::ScriptTimePoint time;
  232. AZ::TickRequestBus::BroadcastResult(time, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  233. m_currentTime = time.GetSeconds();
  234. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  235. AzFramework::DebugDisplayRequestBus::Bind(
  236. debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
  237. AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus.");
  238. AzFramework::DebugDisplayRequests* debugDisplay =
  239. AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  240. if (debugDisplay)
  241. {
  242. OnTickAabbs(*debugDisplay);
  243. OnTickLines(*debugDisplay);
  244. OnTickObbs(*debugDisplay);
  245. OnTickRays(*debugDisplay);
  246. OnTickSpheres(*debugDisplay);
  247. OnTickText(*debugDisplay);
  248. }
  249. }
  250. template <typename F>
  251. void DebugDrawSystemComponent::removeExpiredDebugElementsFromVector(AZStd::vector<F>& vectorToExpire)
  252. {
  253. auto removalCondition = std::remove_if(std::begin(vectorToExpire), std::end(vectorToExpire), [this](F& element)
  254. {
  255. return element.m_duration == 0.0f || (element.m_duration > 0.0f && (element.m_activateTime.GetSeconds() + element.m_duration <= m_currentTime));
  256. });
  257. vectorToExpire.erase(removalCondition, std::end(vectorToExpire));
  258. }
  259. void DebugDrawSystemComponent::OnTickAabbs(AzFramework::DebugDisplayRequests& debugDisplay)
  260. {
  261. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  262. // Draw Aabb elements and remove any that are expired
  263. for (auto& aabbElement : m_activeAabbs)
  264. {
  265. AZ::Aabb transformedAabb(aabbElement.m_aabb);
  266. // Query for entity location if this Aabb is attached to an entity
  267. if (aabbElement.m_targetEntityId.IsValid())
  268. {
  269. AZ::TransformBus::EventResult(aabbElement.m_worldLocation, aabbElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  270. // Re-center
  271. AZ::Vector3 currentCenter = transformedAabb.GetCenter();
  272. transformedAabb.Set(transformedAabb.GetMin() - currentCenter + aabbElement.m_worldLocation, transformedAabb.GetMax() - currentCenter + aabbElement.m_worldLocation);
  273. }
  274. debugDisplay.SetColor(aabbElement.m_color);
  275. debugDisplay.DrawSolidBox(transformedAabb.GetMin(), transformedAabb.GetMax());
  276. }
  277. removeExpiredDebugElementsFromVector(m_activeAabbs);
  278. }
  279. void DebugDrawSystemComponent::OnTickLines(AzFramework::DebugDisplayRequests& debugDisplay)
  280. {
  281. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  282. size_t numActiveLines = m_activeLines.size();
  283. m_batchPoints.clear();
  284. m_batchColors.clear();
  285. m_batchPoints.reserve(numActiveLines * 2);
  286. m_batchColors.reserve(numActiveLines * 2);
  287. // Draw line elements and remove any that are expired
  288. for (auto& lineElement : m_activeLines)
  289. {
  290. // Query for entity locations if this line starts or ends at valid entities.
  291. // Nice thing with this setup where we're using the lineElement's locations to query is that
  292. // when one of the entities gets destroyed, we'll keep drawing to its last known location (if
  293. // that entity deactivation didn't result in the line no longer being drawn)
  294. if (lineElement.m_startEntityId.IsValid())
  295. {
  296. AZ::TransformBus::EventResult(
  297. lineElement.m_startWorldLocation,
  298. lineElement.m_startEntityId,
  299. &AZ::TransformBus::Events::GetWorldTranslation);
  300. }
  301. if (lineElement.m_endEntityId.IsValid())
  302. {
  303. AZ::TransformBus::EventResult(
  304. lineElement.m_endWorldLocation,
  305. lineElement.m_endEntityId,
  306. &AZ::TransformBus::Events::GetWorldTranslation);
  307. }
  308. debugDisplay.SetColor(lineElement.m_color);
  309. debugDisplay.DrawLine(lineElement.m_startWorldLocation, lineElement.m_endWorldLocation);
  310. }
  311. removeExpiredDebugElementsFromVector(m_activeLines);
  312. }
  313. void DebugDrawSystemComponent::OnTickObbs(AzFramework::DebugDisplayRequests& debugDisplay)
  314. {
  315. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  316. // Draw Obb elements and remove any that are expired
  317. for (auto& obbElement : m_activeObbs)
  318. {
  319. AZ::Obb transformedObb = obbElement.m_obb;
  320. // Entity-attached Obbs get positioned and rotated according to entity transform
  321. if (obbElement.m_targetEntityId.IsValid())
  322. {
  323. AZ::Transform entityTM;
  324. AZ::TransformBus::EventResult(entityTM, obbElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTM);
  325. obbElement.m_worldLocation = entityTM.GetTranslation();
  326. transformedObb.SetPosition(AZ::Vector3::CreateZero());
  327. transformedObb = entityTM * transformedObb;
  328. //set half lengths based on editor values
  329. for (unsigned i = 0; i <= 2; ++i)
  330. {
  331. transformedObb.SetHalfLength(i, obbElement.m_scale.GetElement(i));
  332. }
  333. }
  334. else
  335. {
  336. obbElement.m_worldLocation = transformedObb.GetPosition();
  337. }
  338. debugDisplay.SetColor(obbElement.m_color);
  339. debugDisplay.DrawSolidOBB(obbElement.m_worldLocation, transformedObb.GetAxisX(), transformedObb.GetAxisY(), transformedObb.GetAxisZ(), transformedObb.GetHalfLengths());
  340. }
  341. removeExpiredDebugElementsFromVector(m_activeObbs);
  342. }
  343. void DebugDrawSystemComponent::OnTickRays(AzFramework::DebugDisplayRequests& debugDisplay)
  344. {
  345. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  346. // Draw ray elements and remove any that are expired
  347. for (auto& rayElement : m_activeRays)
  348. {
  349. // Query for entity locations if this ray starts or ends at valid entities.
  350. if (rayElement.m_startEntityId.IsValid())
  351. {
  352. AZ::TransformBus::EventResult(rayElement.m_worldLocation, rayElement.m_startEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  353. }
  354. AZ::Vector3 endWorldLocation(rayElement.m_worldLocation + rayElement.m_worldDirection);
  355. if (rayElement.m_endEntityId.IsValid())
  356. {
  357. AZ::TransformBus::EventResult(endWorldLocation, rayElement.m_endEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  358. rayElement.m_worldDirection = (endWorldLocation - rayElement.m_worldLocation);
  359. }
  360. float conePercentHeight = 0.5f;
  361. float coneHeight = rayElement.m_worldDirection.GetLength() * conePercentHeight;
  362. AZ::Vector3 coneBaseLocation = endWorldLocation - rayElement.m_worldDirection * conePercentHeight;
  363. float coneRadius = AZ::GetClamp(coneHeight * 0.07f, 0.05f, 0.2f);
  364. debugDisplay.SetColor(rayElement.m_color);
  365. debugDisplay.SetLineWidth(5.0f);
  366. debugDisplay.DrawLine(rayElement.m_worldLocation, coneBaseLocation);
  367. debugDisplay.DrawSolidCone(coneBaseLocation, rayElement.m_worldDirection, coneRadius, coneHeight, false);
  368. }
  369. removeExpiredDebugElementsFromVector(m_activeRays);
  370. }
  371. void DebugDrawSystemComponent::OnTickSpheres(AzFramework::DebugDisplayRequests& debugDisplay)
  372. {
  373. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  374. // Draw sphere elements and remove any that are expired
  375. for (auto& sphereElement : m_activeSpheres)
  376. {
  377. // Query for entity location if this sphere is attached to an entity
  378. if (sphereElement.m_targetEntityId.IsValid())
  379. {
  380. AZ::TransformBus::EventResult(sphereElement.m_worldLocation, sphereElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  381. }
  382. debugDisplay.SetColor(sphereElement.m_color);
  383. debugDisplay.DrawBall(sphereElement.m_worldLocation, sphereElement.m_radius, true);
  384. }
  385. removeExpiredDebugElementsFromVector(m_activeSpheres);
  386. }
  387. void DebugDrawSystemComponent::OnTickText(AzFramework::DebugDisplayRequests& debugDisplay)
  388. {
  389. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  390. // Determine if we need gamma conversion
  391. bool needsGammaConversion = false;
  392. #ifdef DEBUGDRAW_GEM_EDITOR
  393. bool isInGameMode = true;
  394. AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(isInGameMode, &AzToolsFramework::EditorEntityContextRequestBus::Events::IsEditorRunningGame);
  395. if (isInGameMode)
  396. {
  397. needsGammaConversion = true;
  398. }
  399. #endif // DEBUGDRAW_GEM_EDITOR
  400. // Draw text elements and remove any that are expired
  401. int numScreenTexts = 0;
  402. AZ::EntityId lastTargetEntityId;
  403. for (auto& textElement : m_activeTexts)
  404. {
  405. const AZ::Color textColor = needsGammaConversion ? textElement.m_color.GammaToLinear() : textElement.m_color;
  406. debugDisplay.SetColor(textColor);
  407. if (textElement.m_drawMode == DebugDrawTextElement::DrawMode::OnScreen)
  408. {
  409. debugDisplay.Draw2dTextLabel(100.0f, 20.f + ((float)numScreenTexts * 15.0f), 1.4f, textElement.m_text.c_str() );
  410. ++numScreenTexts;
  411. }
  412. else if (textElement.m_drawMode == DebugDrawTextElement::DrawMode::InWorld)
  413. {
  414. AZ::Vector3 worldLocation;
  415. if (textElement.m_targetEntityId.IsValid())
  416. {
  417. // Entity text
  418. AZ::TransformBus::EventResult(worldLocation, textElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  419. }
  420. else
  421. {
  422. // World text
  423. worldLocation = textElement.m_worldLocation;
  424. }
  425. debugDisplay.DrawTextLabel(worldLocation, 1.4f, textElement.m_text.c_str() );
  426. }
  427. }
  428. removeExpiredDebugElementsFromVector(m_activeTexts);
  429. }
  430. void DebugDrawSystemComponent::RegisterDebugDrawComponent(AZ::Component* component)
  431. {
  432. AZ_Assert(component != nullptr, "Null component being registered!");
  433. AZ::EntityBus::MultiHandler::BusConnect(component->GetEntityId());
  434. if (DebugDrawLineComponent* lineComponent = azrtti_cast<DebugDrawLineComponent*>(component))
  435. {
  436. CreateLineEntryForComponent(lineComponent->GetEntityId(), lineComponent->m_element);
  437. }
  438. #ifdef DEBUGDRAW_GEM_EDITOR
  439. else if (EditorDebugDrawLineComponent* editorLineComponent = azrtti_cast<EditorDebugDrawLineComponent*>(component))
  440. {
  441. CreateLineEntryForComponent(editorLineComponent->GetEntityId(), editorLineComponent->m_element);
  442. }
  443. #endif // DEBUGDRAW_GEM_EDITOR
  444. else if (DebugDrawRayComponent* rayComponent = azrtti_cast<DebugDrawRayComponent*>(component))
  445. {
  446. CreateRayEntryForComponent(rayComponent->GetEntityId(), rayComponent->m_element);
  447. }
  448. #ifdef DEBUGDRAW_GEM_EDITOR
  449. else if (EditorDebugDrawRayComponent* editorRayComponent = azrtti_cast<EditorDebugDrawRayComponent*>(component))
  450. {
  451. CreateRayEntryForComponent(editorRayComponent->GetEntityId(), editorRayComponent->m_element);
  452. }
  453. #endif // DEBUGDRAW_GEM_EDITOR
  454. else if (DebugDrawSphereComponent* sphereComponent = azrtti_cast<DebugDrawSphereComponent*>(component))
  455. {
  456. CreateSphereEntryForComponent(sphereComponent->GetEntityId(), sphereComponent->m_element);
  457. }
  458. #ifdef DEBUGDRAW_GEM_EDITOR
  459. else if (EditorDebugDrawSphereComponent* editorSphereComponent = azrtti_cast<EditorDebugDrawSphereComponent*>(component))
  460. {
  461. CreateSphereEntryForComponent(editorSphereComponent->GetEntityId(), editorSphereComponent->m_element);
  462. }
  463. #endif // DEBUGDRAW_GEM_EDITOR
  464. else if (DebugDrawObbComponent* obbComponent = azrtti_cast<DebugDrawObbComponent*>(component))
  465. {
  466. CreateObbEntryForComponent(obbComponent->GetEntityId(), obbComponent->m_element);
  467. }
  468. #ifdef DEBUGDRAW_GEM_EDITOR
  469. else if (EditorDebugDrawObbComponent* editorObbComponent = azrtti_cast<EditorDebugDrawObbComponent*>(component))
  470. {
  471. CreateObbEntryForComponent(editorObbComponent->GetEntityId(), editorObbComponent->m_element);
  472. }
  473. #endif // DEBUGDRAW_GEM_EDITOR
  474. else if (DebugDrawTextComponent* textComponent = azrtti_cast<DebugDrawTextComponent*>(component))
  475. {
  476. CreateTextEntryForComponent(textComponent->GetEntityId(), textComponent->m_element);
  477. }
  478. #ifdef DEBUGDRAW_GEM_EDITOR
  479. else if (EditorDebugDrawTextComponent* editorTextComponent = azrtti_cast<EditorDebugDrawTextComponent*>(component))
  480. {
  481. CreateTextEntryForComponent(editorTextComponent->GetEntityId(), editorTextComponent->m_element);
  482. }
  483. #endif // DEBUGDRAW_GEM_EDITOR
  484. }
  485. void DebugDrawSystemComponent::OnEntityDeactivated(const AZ::EntityId& entityId)
  486. {
  487. AZ::EntityBus::MultiHandler::BusDisconnect(entityId);
  488. // Remove all associated entity-based debug elements for this entity
  489. // Lines
  490. {
  491. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  492. for (auto iter = m_activeLines.begin(); iter != m_activeLines.end();)
  493. {
  494. DebugDrawLineElement& element = *iter;
  495. if (element.m_startEntityId == entityId)
  496. {
  497. m_activeLines.erase(iter);
  498. }
  499. else
  500. {
  501. ++iter;
  502. }
  503. }
  504. }
  505. // Rays
  506. {
  507. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  508. for (auto iter = m_activeRays.begin(); iter != m_activeRays.end();)
  509. {
  510. DebugDrawRayElement& element = *iter;
  511. if (element.m_startEntityId == entityId)
  512. {
  513. m_activeRays.erase(iter);
  514. }
  515. else
  516. {
  517. ++iter;
  518. }
  519. }
  520. }
  521. // Obbs
  522. {
  523. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  524. for (auto iter = m_activeObbs.begin(); iter != m_activeObbs.end();)
  525. {
  526. DebugDrawObbElement& element = *iter;
  527. if (element.m_targetEntityId == entityId)
  528. {
  529. m_activeObbs.erase(iter);
  530. }
  531. else
  532. {
  533. ++iter;
  534. }
  535. }
  536. }
  537. // Spheres
  538. {
  539. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  540. for (auto iter = m_activeSpheres.begin(); iter != m_activeSpheres.end();)
  541. {
  542. DebugDrawSphereElement& element = *iter;
  543. if (element.m_targetEntityId == entityId)
  544. {
  545. m_activeSpheres.erase(iter);
  546. }
  547. else
  548. {
  549. ++iter;
  550. }
  551. }
  552. }
  553. // Text
  554. {
  555. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  556. for (auto iter = m_activeTexts.begin(); iter != m_activeTexts.end();)
  557. {
  558. DebugDrawTextElement& element = *iter;
  559. if (element.m_targetEntityId == entityId)
  560. {
  561. m_activeTexts.erase(iter);
  562. }
  563. else
  564. {
  565. ++iter;
  566. }
  567. }
  568. }
  569. }
  570. void DebugDrawSystemComponent::UnregisterDebugDrawComponent(AZ::Component* component)
  571. {
  572. const AZ::EntityId componentEntityId = component->GetEntityId();
  573. const AZ::ComponentId componentId = component->GetId();
  574. // Remove specific associated entity-based debug element for this entity/component combo
  575. // Lines
  576. {
  577. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  578. for (auto iter = m_activeLines.begin(); iter != m_activeLines.end();)
  579. {
  580. DebugDrawLineElement& element = *iter;
  581. if (element.m_startEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  582. {
  583. m_activeLines.erase(iter);
  584. break; // Only one element per component
  585. }
  586. else
  587. {
  588. ++iter;
  589. }
  590. }
  591. }
  592. // Rays
  593. {
  594. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  595. for (auto iter = m_activeRays.begin(); iter != m_activeRays.end();)
  596. {
  597. DebugDrawRayElement& element = *iter;
  598. if (element.m_startEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  599. {
  600. m_activeRays.erase(iter);
  601. break; // Only one element per component
  602. }
  603. else
  604. {
  605. ++iter;
  606. }
  607. }
  608. }
  609. // Obbs
  610. {
  611. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  612. for (auto iter = m_activeObbs.begin(); iter != m_activeObbs.end();)
  613. {
  614. DebugDrawObbElement& element = *iter;
  615. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  616. {
  617. m_activeObbs.erase(iter);
  618. break; // Only one element per component
  619. }
  620. else
  621. {
  622. ++iter;
  623. }
  624. }
  625. }
  626. // Spheres
  627. {
  628. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  629. for (auto iter = m_activeSpheres.begin(); iter != m_activeSpheres.end();)
  630. {
  631. DebugDrawSphereElement& element = *iter;
  632. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  633. {
  634. m_activeSpheres.erase(iter);
  635. break; // Only one element per component
  636. }
  637. else
  638. {
  639. ++iter;
  640. }
  641. }
  642. }
  643. // Text
  644. {
  645. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  646. for (auto iter = m_activeTexts.begin(); iter != m_activeTexts.end();)
  647. {
  648. DebugDrawTextElement& element = *iter;
  649. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  650. {
  651. m_activeTexts.erase(iter);
  652. break; // Only one element per component
  653. }
  654. else
  655. {
  656. ++iter;
  657. }
  658. }
  659. }
  660. }
  661. ///////////////////////////////////////////////////////////////////////
  662. // Aabbs
  663. ///////////////////////////////////////////////////////////////////////
  664. void DebugDrawSystemComponent::DrawAabb(const AZ::Aabb& aabb, const AZ::Color& color, float duration)
  665. {
  666. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  667. DebugDrawAabbElement& newElement = m_activeAabbs.emplace_back();
  668. newElement.m_aabb = aabb;
  669. newElement.m_color = color;
  670. newElement.m_duration = duration;
  671. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  672. }
  673. void DebugDrawSystemComponent::DrawAabbOnEntity(const AZ::EntityId& targetEntity, const AZ::Aabb& aabb, const AZ::Color& color, float duration)
  674. {
  675. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  676. DebugDrawAabbElement& newElement = m_activeAabbs.emplace_back();
  677. newElement.m_targetEntityId = targetEntity;
  678. newElement.m_aabb = aabb;
  679. newElement.m_color = color;
  680. newElement.m_duration = duration;
  681. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  682. }
  683. void DebugDrawSystemComponent::CreateAabbEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawAabbElement& element)
  684. {
  685. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  686. m_activeAabbs.push_back(element);
  687. DebugDrawAabbElement& newElement = m_activeAabbs.back();
  688. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  689. newElement.m_targetEntityId = componentEntityId;
  690. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  691. }
  692. ///////////////////////////////////////////////////////////////////////
  693. // Lines
  694. ///////////////////////////////////////////////////////////////////////
  695. void DebugDrawSystemComponent::DrawLineBatchLocationToLocation(const AZStd::vector<DebugDraw::DebugDrawLineElement>& lineBatch)
  696. {
  697. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  698. m_activeLines.insert(m_activeLines.end(), lineBatch.begin(), lineBatch.end());
  699. }
  700. void DebugDrawSystemComponent::DrawLineLocationToLocation(const AZ::Vector3& startLocation, const AZ::Vector3& endLocation, const AZ::Color& color, float duration)
  701. {
  702. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  703. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  704. newElement.m_color = color;
  705. newElement.m_duration = duration;
  706. newElement.m_startWorldLocation = startLocation;
  707. newElement.m_endWorldLocation = endLocation;
  708. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  709. }
  710. void DebugDrawSystemComponent::DrawLineEntityToLocation(const AZ::EntityId& startEntity, const AZ::Vector3& endLocation, const AZ::Color& color, float duration)
  711. {
  712. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  713. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  714. newElement.m_color = color;
  715. newElement.m_duration = duration;
  716. newElement.m_startEntityId = startEntity; // Start of line is at this entity's location
  717. newElement.m_endWorldLocation = endLocation;
  718. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  719. }
  720. void DebugDrawSystemComponent::DrawLineEntityToEntity(const AZ::EntityId& startEntity, const AZ::EntityId& endEntity, const AZ::Color& color, float duration)
  721. {
  722. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  723. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  724. newElement.m_color = color;
  725. newElement.m_duration = duration;
  726. newElement.m_startEntityId = startEntity; // Start of line is at start entity's location
  727. newElement.m_endEntityId = endEntity; // End of line is at end entity's location
  728. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  729. }
  730. void DebugDrawSystemComponent::CreateLineEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawLineElement& element)
  731. {
  732. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  733. m_activeLines.push_back(element);
  734. DebugDrawLineElement& newElement = m_activeLines.back();
  735. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  736. newElement.m_startEntityId = componentEntityId;
  737. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  738. }
  739. ///////////////////////////////////////////////////////////////////////
  740. // Obbs
  741. ///////////////////////////////////////////////////////////////////////
  742. void DebugDrawSystemComponent::DrawObb(const AZ::Obb& obb, const AZ::Color& color, float duration)
  743. {
  744. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  745. DebugDrawObbElement& newElement = m_activeObbs.emplace_back();
  746. newElement.m_obb = obb;
  747. newElement.m_color = color;
  748. newElement.m_duration = duration;
  749. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  750. }
  751. void DebugDrawSystemComponent::DrawObbOnEntity(const AZ::EntityId& targetEntity, const AZ::Obb& obb, const AZ::Color& color, float duration)
  752. {
  753. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  754. DebugDrawObbElement& newElement = m_activeObbs.emplace_back();
  755. newElement.m_targetEntityId = targetEntity;
  756. newElement.m_obb = obb;
  757. newElement.m_color = color;
  758. newElement.m_duration = duration;
  759. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  760. }
  761. void DebugDrawSystemComponent::CreateObbEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawObbElement& element)
  762. {
  763. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  764. m_activeObbs.push_back(element);
  765. DebugDrawObbElement& newElement = m_activeObbs.back();
  766. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  767. newElement.m_targetEntityId = componentEntityId;
  768. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  769. }
  770. ///////////////////////////////////////////////////////////////////////
  771. // Rays
  772. ///////////////////////////////////////////////////////////////////////
  773. void DebugDrawSystemComponent::DrawRayLocationToDirection(const AZ::Vector3& worldLocation, const AZ::Vector3& worldDirection, const AZ::Color& color, float duration)
  774. {
  775. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  776. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  777. newElement.m_color = color;
  778. newElement.m_duration = duration;
  779. newElement.m_worldLocation = worldLocation;
  780. newElement.m_worldDirection = worldDirection;
  781. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  782. }
  783. void DebugDrawSystemComponent::DrawRayEntityToDirection(const AZ::EntityId& startEntity, const AZ::Vector3& worldDirection, const AZ::Color& color, float duration)
  784. {
  785. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  786. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  787. newElement.m_color = color;
  788. newElement.m_duration = duration;
  789. newElement.m_startEntityId = startEntity;
  790. newElement.m_worldDirection = worldDirection;
  791. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  792. }
  793. void DebugDrawSystemComponent::DrawRayEntityToEntity(const AZ::EntityId& startEntity, const AZ::EntityId& endEntity, const AZ::Color& color, float duration)
  794. {
  795. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  796. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  797. newElement.m_color = color;
  798. newElement.m_duration = duration;
  799. newElement.m_startEntityId = startEntity;
  800. newElement.m_endEntityId = endEntity;
  801. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  802. }
  803. void DebugDrawSystemComponent::CreateRayEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawRayElement& element)
  804. {
  805. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  806. m_activeRays.push_back(element);
  807. DebugDrawRayElement& newElement = m_activeRays.back();
  808. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  809. newElement.m_startEntityId = componentEntityId;
  810. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  811. }
  812. ///////////////////////////////////////////////////////////////////////
  813. // Spheres
  814. ///////////////////////////////////////////////////////////////////////
  815. void DebugDrawSystemComponent::DrawSphereAtLocation(const AZ::Vector3& worldLocation, float radius, const AZ::Color& color, float duration)
  816. {
  817. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  818. DebugDrawSphereElement& newElement = m_activeSpheres.emplace_back();
  819. newElement.m_worldLocation = worldLocation;
  820. newElement.m_radius = radius;
  821. newElement.m_color = color;
  822. newElement.m_duration = duration;
  823. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  824. }
  825. void DebugDrawSystemComponent::DrawSphereOnEntity(const AZ::EntityId& targetEntity, float radius, const AZ::Color& color, float duration)
  826. {
  827. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  828. DebugDrawSphereElement& newElement = m_activeSpheres.emplace_back();
  829. newElement.m_targetEntityId = targetEntity;
  830. newElement.m_radius = radius;
  831. newElement.m_color = color;
  832. newElement.m_duration = duration;
  833. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  834. }
  835. void DebugDrawSystemComponent::CreateSphereEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawSphereElement& element)
  836. {
  837. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  838. m_activeSpheres.push_back(element);
  839. DebugDrawSphereElement& newElement = m_activeSpheres.back();
  840. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  841. newElement.m_targetEntityId = componentEntityId;
  842. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  843. }
  844. ///////////////////////////////////////////////////////////////////////
  845. // Text
  846. ///////////////////////////////////////////////////////////////////////
  847. void DebugDrawSystemComponent::DrawTextAtLocation(const AZ::Vector3& worldLocation, const AZStd::string& text, const AZ::Color& color, float duration)
  848. {
  849. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  850. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  851. newText.m_drawMode = DebugDrawTextElement::DrawMode::InWorld;
  852. newText.m_text = text;
  853. newText.m_color = color;
  854. newText.m_duration = duration;
  855. newText.m_worldLocation = worldLocation;
  856. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  857. }
  858. void DebugDrawSystemComponent::DrawTextOnEntity(const AZ::EntityId& targetEntity, const AZStd::string& text, const AZ::Color& color, float duration)
  859. {
  860. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  861. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  862. newText.m_drawMode = DebugDrawTextElement::DrawMode::InWorld;
  863. newText.m_text = text;
  864. newText.m_color = color;
  865. newText.m_duration = duration;
  866. newText.m_targetEntityId = targetEntity;
  867. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  868. }
  869. void DebugDrawSystemComponent::DrawTextOnScreen(const AZStd::string& text, const AZ::Color& color, float duration)
  870. {
  871. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  872. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  873. newText.m_drawMode = DebugDrawTextElement::DrawMode::OnScreen;
  874. //newText.m_category = 0;
  875. newText.m_text = text;
  876. newText.m_color = color;
  877. newText.m_duration = duration;
  878. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  879. }
  880. void DebugDrawSystemComponent::CreateTextEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawTextElement& element)
  881. {
  882. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  883. m_activeTexts.push_back(element);
  884. DebugDrawTextElement& newText = m_activeTexts.back();
  885. newText.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  886. newText.m_targetEntityId = componentEntityId;
  887. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  888. }
  889. } // namespace DebugDraw