OpenXRVkInteractionProfilesAsset.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 <OpenXRVk/OpenXRVkInteractionProfilesAsset.h>
  9. #include <OpenXRVk/OpenXRVkAssetsValidator.h>
  10. namespace OpenXRVk
  11. {
  12. ///////////////////////////////////////////////////////////
  13. /// OpenXRInteractionComponentPathDescriptor
  14. XrActionType OpenXRInteractionComponentPathDescriptor::GetXrActionType(AZStd::string_view actionTypeStr)
  15. {
  16. if (actionTypeStr == s_TypeBoolStr)
  17. {
  18. return XR_ACTION_TYPE_BOOLEAN_INPUT;
  19. }
  20. else if (actionTypeStr == s_TypeFloatStr)
  21. {
  22. return XR_ACTION_TYPE_FLOAT_INPUT;
  23. }
  24. else if (actionTypeStr == s_TypeVector2Str)
  25. {
  26. return XR_ACTION_TYPE_VECTOR2F_INPUT;
  27. }
  28. else if (actionTypeStr == s_TypePoseStr)
  29. {
  30. return XR_ACTION_TYPE_POSE_INPUT;
  31. }
  32. else if (actionTypeStr == s_TypeVibrationStr)
  33. {
  34. return XR_ACTION_TYPE_VIBRATION_OUTPUT;
  35. }
  36. return XR_ACTION_TYPE_MAX_ENUM;
  37. }
  38. XrActionType OpenXRInteractionComponentPathDescriptor::GetXrActionType() const
  39. {
  40. return GetXrActionType(m_actionTypeStr);
  41. }
  42. static AZStd::vector<AZStd::string> GetEditorXrActionTypeNames()
  43. {
  44. static AZStd::vector<AZStd::string> s_actionTypeNames = {
  45. {OpenXRInteractionComponentPathDescriptor::s_TypeBoolStr },
  46. {OpenXRInteractionComponentPathDescriptor::s_TypeFloatStr },
  47. {OpenXRInteractionComponentPathDescriptor::s_TypeVector2Str},
  48. {OpenXRInteractionComponentPathDescriptor::s_TypePoseStr },
  49. {OpenXRInteractionComponentPathDescriptor::s_TypeVibrationStr },
  50. };
  51. return s_actionTypeNames;
  52. }
  53. void OpenXRInteractionComponentPathDescriptor::Reflect(AZ::ReflectContext* context)
  54. {
  55. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  56. if (serialize)
  57. {
  58. serialize->Class<OpenXRInteractionComponentPathDescriptor>()
  59. ->Version(1)
  60. ->Field("Name", &OpenXRInteractionComponentPathDescriptor::m_name)
  61. ->Field("Path", &OpenXRInteractionComponentPathDescriptor::m_path)
  62. ->Field("ActionType", &OpenXRInteractionComponentPathDescriptor::m_actionTypeStr)
  63. ;
  64. AZ::EditContext* edit = serialize->GetEditContext();
  65. if (edit)
  66. {
  67. edit->Class<OpenXRInteractionComponentPathDescriptor>("Component Path", "An OpenXR Component Path that is supported by an OpenXR User Path")
  68. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  69. ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &OpenXRInteractionComponentPathDescriptor::GetEditorText)
  70. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  71. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionComponentPathDescriptor::m_name, "Name", "User friendly name.")
  72. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  73. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionComponentPathDescriptor::m_path, "Path", "An OpenXR Path string that starts with '/' BUT is relative to a User Path.")
  74. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &OpenXRInteractionComponentPathDescriptor::m_actionTypeStr, "Action Type", "Data type of this action.")
  75. ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorXrActionTypeNames)
  76. ;
  77. }
  78. }
  79. }
  80. AZStd::string OpenXRInteractionComponentPathDescriptor::GetEditorText()
  81. {
  82. return m_name.empty() ? "<Unknown Component Path>" : m_name;
  83. }
  84. /// OpenXRInteractionComponentPathDescriptor
  85. ///////////////////////////////////////////////////////////
  86. ///////////////////////////////////////////////////////////
  87. /// OpenXRInteractionUserPathDescriptor
  88. void OpenXRInteractionUserPathDescriptor::Reflect(AZ::ReflectContext* context)
  89. {
  90. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  91. if (serialize)
  92. {
  93. serialize->Class<OpenXRInteractionUserPathDescriptor>()
  94. ->Version(1)
  95. ->Field("Name", &OpenXRInteractionUserPathDescriptor::m_name)
  96. ->Field("Path", &OpenXRInteractionUserPathDescriptor::m_path)
  97. ->Field("ComponentPaths", &OpenXRInteractionUserPathDescriptor::m_componentPathDescriptors)
  98. ;
  99. AZ::EditContext* edit = serialize->GetEditContext();
  100. if (edit)
  101. {
  102. edit->Class<OpenXRInteractionUserPathDescriptor>("User Path", "Represents a User Path supported by an Interaction Profile")
  103. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  104. ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &OpenXRInteractionUserPathDescriptor::GetEditorText)
  105. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  106. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionUserPathDescriptor::m_name, "Name", "User friendly name.")
  107. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  108. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionUserPathDescriptor::m_path, "Path", "An OpenXR Path string that starts with '/'.")
  109. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionUserPathDescriptor::m_componentPathDescriptors, "Component Paths", "List of component paths supported by this User Path")
  110. ;
  111. }
  112. }
  113. }
  114. AZStd::string OpenXRInteractionUserPathDescriptor::GetEditorText()
  115. {
  116. return m_name.empty() ? "<Unknown User Path>" : m_name;
  117. }
  118. const OpenXRInteractionComponentPathDescriptor* OpenXRInteractionUserPathDescriptor::GetComponentPathDescriptor(const AZStd::string& componentPathName) const
  119. {
  120. for (const auto& componentPathDescriptor : m_componentPathDescriptors)
  121. {
  122. if (componentPathDescriptor.m_name == componentPathName)
  123. {
  124. return &componentPathDescriptor;
  125. }
  126. }
  127. return nullptr;
  128. }
  129. /// OpenXRInteractionUserPathDescriptor
  130. ///////////////////////////////////////////////////////////
  131. ///////////////////////////////////////////////////////////
  132. /// OpenXRInteractionProfileDescriptor
  133. void OpenXRInteractionProfileDescriptor::Reflect(AZ::ReflectContext* context)
  134. {
  135. OpenXRInteractionComponentPathDescriptor::Reflect(context);
  136. OpenXRInteractionUserPathDescriptor::Reflect(context);
  137. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  138. if (serialize)
  139. {
  140. serialize->Class<OpenXRInteractionProfileDescriptor>()
  141. ->Version(1)
  142. ->Field("UniqueName", &OpenXRInteractionProfileDescriptor::m_name)
  143. ->Field("Path", &OpenXRInteractionProfileDescriptor::m_path)
  144. ->Field("UserPathDescriptors", &OpenXRInteractionProfileDescriptor::m_userPathDescriptors)
  145. ->Field("CommonComponentPathDescriptors", &OpenXRInteractionProfileDescriptor::m_commonComponentPathDescriptors)
  146. ;
  147. AZ::EditContext* edit = serialize->GetEditContext();
  148. if (edit)
  149. {
  150. edit->Class<OpenXRInteractionProfileDescriptor>(
  151. "Interaction Profile", "Defines an OpenXR Interaction Profile Supported by O3DE.")
  152. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  153. ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &OpenXRInteractionProfileDescriptor::GetEditorText)
  154. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  155. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionProfileDescriptor::m_name, "Unique Name", "Unique name across all interaction profiles")
  156. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  157. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionProfileDescriptor::m_path, "Path", "OpenXR Canonical Path for this interation profile.")
  158. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionProfileDescriptor::m_userPathDescriptors, "User Paths", "List of user paths")
  159. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionProfileDescriptor::m_commonComponentPathDescriptors, "Common Component Paths", "List of component paths supported by all User Paths")
  160. ;
  161. }
  162. }
  163. }
  164. AZStd::string OpenXRInteractionProfileDescriptor::GetEditorText()
  165. {
  166. return m_name.empty() ? "<Unknown Profile>" : m_name;
  167. }
  168. const OpenXRInteractionUserPathDescriptor* OpenXRInteractionProfileDescriptor::GetUserPathDescriptor(const AZStd::string& userPathName) const
  169. {
  170. for (const auto& userPathDescriptor : m_userPathDescriptors)
  171. {
  172. if (userPathDescriptor.m_name == userPathName)
  173. {
  174. return &userPathDescriptor;
  175. }
  176. }
  177. return nullptr;
  178. }
  179. const OpenXRInteractionComponentPathDescriptor* OpenXRInteractionProfileDescriptor::GetCommonComponentPathDescriptor(const AZStd::string& componentPathName) const
  180. {
  181. for (const auto& componentPathDescriptor : m_commonComponentPathDescriptors)
  182. {
  183. if (componentPathDescriptor.m_name == componentPathName)
  184. {
  185. return &componentPathDescriptor;
  186. }
  187. }
  188. return nullptr;
  189. }
  190. const OpenXRInteractionComponentPathDescriptor* OpenXRInteractionProfileDescriptor::GetComponentPathDescriptor(const OpenXRInteractionUserPathDescriptor& userPathDescriptor,
  191. const AZStd::string& componentPathName) const
  192. {
  193. auto componentPathDescriptor = userPathDescriptor.GetComponentPathDescriptor(componentPathName);
  194. if (!componentPathDescriptor)
  195. {
  196. // Look in common paths
  197. return GetCommonComponentPathDescriptor(componentPathName);
  198. }
  199. return componentPathDescriptor;
  200. }
  201. AZStd::string OpenXRInteractionProfileDescriptor::GetComponentAbsolutePath(const OpenXRInteractionUserPathDescriptor& userPathDescriptor,
  202. const AZStd::string& componentPathName) const
  203. {
  204. // First check if the user path owns the component path, if not, search in the common components list.
  205. auto componentPathDescriptor = GetComponentPathDescriptor(userPathDescriptor, componentPathName);
  206. if (!componentPathDescriptor)
  207. {
  208. return {};
  209. }
  210. return userPathDescriptor.m_path + componentPathDescriptor->m_path;
  211. }
  212. /// OpenXRInteractionProfileDescriptor
  213. ///////////////////////////////////////////////////////////
  214. ///////////////////////////////////////////////////////////
  215. /// OpenXRInteractionProfilesAsset
  216. void OpenXRInteractionProfilesAsset::Reflect(AZ::ReflectContext* context)
  217. {
  218. OpenXRInteractionProfileDescriptor::Reflect(context);
  219. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  220. if (serialize)
  221. {
  222. serialize->Class<OpenXRInteractionProfilesAsset, AZ::Data::AssetData>()
  223. ->Version(1)
  224. ->Attribute(AZ::Edit::Attributes::EnableForAssetEditor, true)
  225. ->Field("InteractionProfiles", &OpenXRInteractionProfilesAsset::m_interactionProfileDescriptors)
  226. ;
  227. AZ::EditContext* edit = serialize->GetEditContext();
  228. if (edit)
  229. {
  230. edit->Class<OpenXRInteractionProfilesAsset>(
  231. s_assetTypeName, "Defines the OpenXR Interaction Profiles supported by O3DE.")
  232. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  233. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  234. ->DataElement(AZ::Edit::UIHandlers::Default, &OpenXRInteractionProfilesAsset::m_interactionProfileDescriptors, "Interaction Profiles", "List of interaction profile descriptors.")
  235. ;
  236. }
  237. }
  238. }
  239. const OpenXRInteractionProfileDescriptor* OpenXRInteractionProfilesAsset::GetInteractionProfileDescriptor(const AZStd::string& profileName) const
  240. {
  241. for (const auto& profileDescriptor : m_interactionProfileDescriptors)
  242. {
  243. if (profileName == profileDescriptor.m_name)
  244. {
  245. return &profileDescriptor;
  246. }
  247. }
  248. return nullptr;
  249. }
  250. const AZStd::string& OpenXRInteractionProfilesAsset::GetActionPathTypeStr(const AZStd::string& profileName, const AZStd::string& userPathName, const AZStd::string& componentPathName) const
  251. {
  252. static const AZStd::string emptyStr;
  253. const auto profileDescriptor = GetInteractionProfileDescriptor(profileName);
  254. if (!profileDescriptor)
  255. {
  256. return emptyStr;
  257. }
  258. const auto userPathDescriptor = profileDescriptor->GetUserPathDescriptor(userPathName);
  259. if (!userPathDescriptor)
  260. {
  261. return emptyStr;
  262. }
  263. const auto componentPathDescriptor = profileDescriptor->GetComponentPathDescriptor(*userPathDescriptor, componentPathName);
  264. if (!componentPathDescriptor)
  265. {
  266. return emptyStr;
  267. }
  268. return componentPathDescriptor->m_actionTypeStr;
  269. }
  270. /// OpenXRInteractionProfilesAsset
  271. ///////////////////////////////////////////////////////////
  272. ///////////////////////////////////////////////////////////
  273. /// OpenXRInteractionProfilesAssetHandler
  274. OpenXRInteractionProfilesAssetHandler::OpenXRInteractionProfilesAssetHandler()
  275. : AzFramework::GenericAssetHandler<OpenXRInteractionProfilesAsset>(
  276. OpenXRInteractionProfilesAsset::s_assetTypeName,
  277. "Other",
  278. OpenXRInteractionProfilesAsset::s_assetExtension)
  279. {
  280. }
  281. bool OpenXRInteractionProfilesAssetHandler::SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZ::IO::GenericStream* stream)
  282. {
  283. auto profileAsset = asset.GetAs<OpenXRInteractionProfilesAsset>();
  284. if (!profileAsset)
  285. {
  286. AZ_Error(LogName, false, "This should be an OpenXR Interaction Profile Asset, as this is the only type this handler can process.");
  287. return false;
  288. }
  289. auto outcome = OpenXRVkAssetsValidator::ValidateInteractionProfilesAsset(*profileAsset);
  290. if (!outcome.IsSuccess())
  291. {
  292. AZ_Error(LogName, false, "Can't save this interaction profiles asset. Reason:\n%s\n", outcome.GetError().c_str());
  293. return false;
  294. }
  295. if (!m_serializeContext)
  296. {
  297. AZ_Error(LogName, false, "Can't save the OpenXR Interaction Profile Asset without a serialize context.");
  298. return false;
  299. }
  300. return AZ::Utils::SaveObjectToStream(*stream, AZ::ObjectStream::ST_JSON, profileAsset,
  301. asset->RTTI_GetType(), m_serializeContext);
  302. }
  303. /// OpenXRInteractionProfilesAssetHandler
  304. ///////////////////////////////////////////////////////////
  305. } // namespace OpenXRVk