BsGizmoManager.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. #include "BsGizmoManager.h"
  2. #include "BsMesh.h"
  3. #include "BsAABox.h"
  4. #include "BsSphere.h"
  5. #include "BsVertexDataDesc.h"
  6. #include "BsDrawHelper3D.h"
  7. #include "BsMeshHeap.h"
  8. #include "BsCamera.h"
  9. #include "BsSpriteTexture.h"
  10. namespace BansheeEngine
  11. {
  12. const UINT32 GizmoManager::VERTEX_BUFFER_GROWTH = 4096;
  13. const UINT32 GizmoManager::INDEX_BUFFER_GROWTH = 4096 * 2;
  14. const UINT32 GizmoManager::SPHERE_QUALITY = 1;
  15. const float GizmoManager::MAX_ICON_RANGE = 500.0f;
  16. GizmoManager::GizmoManager(const HCamera& camera)
  17. :mTotalRequiredSolidIndices(0), mTotalRequiredSolidVertices(0),
  18. mTotalRequiredWireVertices(0), mTotalRequiredWireIndices(0), mCamera(camera), mPickable(false)
  19. {
  20. mSolidVertexDesc = bs_shared_ptr<VertexDataDesc>();
  21. mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  22. mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL);
  23. mSolidVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  24. mWireVertexDesc = bs_shared_ptr<VertexDataDesc>();
  25. mWireVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  26. mWireVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  27. mIconVertexDesc = bs_shared_ptr<VertexDataDesc>();
  28. mIconVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  29. mIconVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
  30. mIconVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  31. mSolidMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mSolidVertexDesc);
  32. mWireMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mWireVertexDesc);
  33. mIconMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mIconVertexDesc);
  34. }
  35. GizmoManager::~GizmoManager()
  36. {
  37. if (mSolidMesh != nullptr)
  38. mSolidMeshHeap->dealloc(mSolidMesh);
  39. if (mWireMesh != nullptr)
  40. mWireMeshHeap->dealloc(mWireMesh);
  41. if (mIconMesh != nullptr)
  42. mIconMeshHeap->dealloc(mIconMesh);
  43. }
  44. void GizmoManager::startGizmo(const HSceneObject& gizmoParent)
  45. {
  46. mActiveSO = gizmoParent;
  47. }
  48. void GizmoManager::endGizmo()
  49. {
  50. mActiveSO = nullptr;
  51. }
  52. void GizmoManager::setColor(const Color& color)
  53. {
  54. mColor = color;
  55. }
  56. void GizmoManager::setTransform(const Matrix4& transform)
  57. {
  58. mTransform = transform;
  59. }
  60. void GizmoManager::drawCube(const Vector3& position, const Vector3& extents)
  61. {
  62. mSolidCubeData.push_back(CubeData());
  63. CubeData& cubeData = mSolidCubeData.back();
  64. cubeData.position = position;
  65. cubeData.extents = extents;
  66. cubeData.color = mColor;
  67. cubeData.transform = mTransform;
  68. cubeData.sceneObject = mActiveSO;
  69. cubeData.pickable = mPickable;
  70. mTotalRequiredSolidVertices += 24;
  71. mTotalRequiredSolidIndices += 36;
  72. }
  73. void GizmoManager::drawSphere(const Vector3& position, float radius)
  74. {
  75. mSolidSphereData.push_back(SphereData());
  76. SphereData& sphereData = mSolidSphereData.back();
  77. sphereData.position = position;
  78. sphereData.radius = radius;
  79. sphereData.color = mColor;
  80. sphereData.transform = mTransform;
  81. sphereData.sceneObject = mActiveSO;
  82. sphereData.pickable = mPickable;
  83. UINT32 numVertices, numIndices;
  84. DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numVertices, numIndices);
  85. mTotalRequiredSolidVertices += numVertices;
  86. mTotalRequiredSolidIndices += numIndices;
  87. }
  88. void GizmoManager::drawWireCube(const Vector3& position, const Vector3& extents)
  89. {
  90. mWireCubeData.push_back(CubeData());
  91. CubeData& cubeData = mWireCubeData.back();
  92. cubeData.position = position;
  93. cubeData.extents = extents;
  94. cubeData.color = mColor;
  95. cubeData.transform = mTransform;
  96. cubeData.sceneObject = mActiveSO;
  97. cubeData.pickable = mPickable;
  98. mTotalRequiredWireVertices += 8;
  99. mTotalRequiredWireIndices += 24;
  100. }
  101. void GizmoManager::drawWireSphere(const Vector3& position, float radius)
  102. {
  103. mWireSphereData.push_back(SphereData());
  104. SphereData& sphereData = mWireSphereData.back();
  105. sphereData.position = position;
  106. sphereData.radius = radius;
  107. sphereData.color = mColor;
  108. sphereData.transform = mTransform;
  109. sphereData.sceneObject = mActiveSO;
  110. sphereData.pickable = mPickable;
  111. UINT32 numVertices, numIndices;
  112. DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numVertices, numIndices);
  113. mTotalRequiredWireVertices += numVertices;
  114. mTotalRequiredWireIndices += numIndices;
  115. }
  116. void GizmoManager::drawLine(const Vector3& start, const Vector3& end)
  117. {
  118. mLineData.push_back(LineData());
  119. LineData& lineData = mLineData.back();
  120. lineData.start = start;
  121. lineData.end = end;
  122. lineData.color = mColor;
  123. lineData.transform = mTransform;
  124. lineData.sceneObject = mActiveSO;
  125. lineData.pickable = mPickable;
  126. mTotalRequiredWireVertices += 2;
  127. mTotalRequiredWireIndices += 2;
  128. }
  129. void GizmoManager::drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far)
  130. {
  131. mFrustumData.push_back(FrustumData());
  132. FrustumData& frustumData = mFrustumData.back();
  133. frustumData.position = position;
  134. frustumData.aspect = aspect;
  135. frustumData.FOV = FOV;
  136. frustumData.near = near;
  137. frustumData.far = far;
  138. frustumData.color = mColor;
  139. frustumData.transform = mTransform;
  140. frustumData.sceneObject = mActiveSO;
  141. frustumData.pickable = mPickable;
  142. mTotalRequiredWireVertices += 8;
  143. mTotalRequiredWireIndices += 36;
  144. }
  145. void GizmoManager::drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale)
  146. {
  147. mIconData.push_back(IconData());
  148. IconData& iconData = mIconData.back();
  149. iconData.position = position;
  150. iconData.texture = image;
  151. iconData.fixedScale = fixedScale;
  152. iconData.color = mColor;
  153. iconData.transform = mTransform;
  154. iconData.sceneObject = mActiveSO;
  155. iconData.pickable = mPickable;
  156. }
  157. void GizmoManager::update()
  158. {
  159. buildSolidMesh();
  160. buildWireMesh();
  161. buildIconMesh();
  162. }
  163. void GizmoManager::clearGizmos()
  164. {
  165. mSolidCubeData.clear();
  166. mWireCubeData.clear();
  167. mSolidSphereData.clear();
  168. mWireSphereData.clear();
  169. mLineData.clear();
  170. mFrustumData.clear();
  171. mIconData.clear();
  172. mTotalRequiredSolidVertices = 0;
  173. mTotalRequiredSolidIndices = 0;
  174. mTotalRequiredWireVertices = 0;
  175. mTotalRequiredWireIndices = 0;
  176. }
  177. void GizmoManager::buildSolidMesh()
  178. {
  179. MeshDataPtr meshData = bs_shared_ptr<MeshData>(mTotalRequiredSolidVertices, mTotalRequiredSolidIndices, mSolidVertexDesc);
  180. UINT32 curVertexOffset = 0;
  181. UINT32 curIndexOffet = 0;
  182. auto positionIter = meshData->getVec3DataIter(VES_POSITION);
  183. auto normalIter = meshData->getVec3DataIter(VES_NORMAL);
  184. auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
  185. for (auto& cubeData : mSolidCubeData)
  186. {
  187. AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
  188. DrawHelper3D::instance().solidAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
  189. Matrix4 transformIT = cubeData.transform.inverseAffine().transpose();
  190. RGBA color = cubeData.color.getAsRGBA();
  191. UINT32 numVertices = 24;
  192. for (UINT32 i = 0; i < numVertices; i++)
  193. {
  194. Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
  195. Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
  196. positionIter.addValue(worldPos);
  197. normalIter.addValue(worldNormal);
  198. colorIter.addValue(color);
  199. }
  200. curVertexOffset += numVertices;
  201. curIndexOffet += 36;
  202. }
  203. UINT32 numSphereVertices, numSphereIndices;
  204. DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
  205. for (auto& sphereData : mSolidSphereData)
  206. {
  207. Sphere sphere(sphereData.position, sphereData.radius);
  208. DrawHelper3D::instance().solidSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
  209. Matrix4 transformIT = sphereData.transform.inverseAffine().transpose();
  210. RGBA color = sphereData.color.getAsRGBA();
  211. for (UINT32 i = 0; i < numSphereVertices; i++)
  212. {
  213. Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
  214. Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
  215. positionIter.addValue(worldPos);
  216. normalIter.addValue(worldNormal);
  217. colorIter.addValue(color);
  218. }
  219. curVertexOffset += numSphereVertices;
  220. curIndexOffet += numSphereIndices;
  221. }
  222. if (mSolidMesh != nullptr)
  223. mSolidMeshHeap->dealloc(mSolidMesh);
  224. mSolidMesh = mSolidMeshHeap->alloc(meshData, DOT_TRIANGLE_LIST);
  225. }
  226. void GizmoManager::buildWireMesh()
  227. {
  228. MeshDataPtr meshData = bs_shared_ptr<MeshData>(mTotalRequiredWireVertices, mTotalRequiredWireIndices, mWireVertexDesc);
  229. UINT32 curVertexOffset = 0;
  230. UINT32 curIndexOffet = 0;
  231. auto positionIter = meshData->getVec3DataIter(VES_POSITION);
  232. auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
  233. for (auto& cubeData : mWireCubeData)
  234. {
  235. AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
  236. DrawHelper3D::instance().wireAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
  237. RGBA color = cubeData.color.getAsRGBA();
  238. UINT32 numVertices = 8;
  239. for (UINT32 i = 0; i < numVertices; i++)
  240. {
  241. Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
  242. positionIter.addValue(worldPos);
  243. colorIter.addValue(color);
  244. }
  245. curVertexOffset += numVertices;
  246. curIndexOffet += 24;
  247. }
  248. UINT32 numSphereVertices, numSphereIndices;
  249. DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
  250. for (auto& sphereData : mWireSphereData)
  251. {
  252. Sphere sphere(sphereData.position, sphereData.radius);
  253. DrawHelper3D::instance().wireSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
  254. RGBA color = sphereData.color.getAsRGBA();
  255. for (UINT32 i = 0; i < numSphereVertices; i++)
  256. {
  257. Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
  258. positionIter.addValue(worldPos);
  259. colorIter.addValue(color);
  260. }
  261. curVertexOffset += numSphereVertices;
  262. curIndexOffet += numSphereIndices;
  263. }
  264. for (auto& lineData : mLineData)
  265. {
  266. DrawHelper3D::instance().pixelLine(lineData.start, lineData.end, meshData, curVertexOffset, curIndexOffet);
  267. RGBA color = lineData.color.getAsRGBA();
  268. for (UINT32 i = 0; i < 2; i++)
  269. {
  270. Vector3 worldPos = lineData.transform.multiply3x4(positionIter.getValue());
  271. positionIter.addValue(worldPos);
  272. colorIter.addValue(color);
  273. }
  274. curVertexOffset += 2;
  275. curIndexOffet += 2;
  276. }
  277. for (auto& frustumData : mFrustumData)
  278. {
  279. DrawHelper3D::instance().wireFrustum(frustumData.aspect, frustumData.FOV, frustumData.near,
  280. frustumData.far, meshData, curVertexOffset, curIndexOffet);
  281. RGBA color = frustumData.color.getAsRGBA();
  282. for (UINT32 i = 0; i < 8; i++)
  283. {
  284. Vector3 worldPos = frustumData.transform.multiply3x4(positionIter.getValue());
  285. positionIter.addValue(worldPos);
  286. colorIter.addValue(color);
  287. }
  288. curVertexOffset += 8;
  289. curIndexOffet += 24;
  290. }
  291. if (mWireMesh != nullptr)
  292. mWireMeshHeap->dealloc(mWireMesh);
  293. mWireMesh = mWireMeshHeap->alloc(meshData, DOT_LINE_LIST);
  294. }
  295. void GizmoManager::buildIconMesh()
  296. {
  297. mSortedIconData.clear();
  298. if (mIconData.size() > mSortedIconData.size())
  299. mSortedIconData.resize(mIconData.size());
  300. UINT32 i = 0;
  301. for (auto& iconData : mIconData)
  302. {
  303. Vector3 viewPoint = mCamera->worldToViewPoint(iconData.position);
  304. float distance = -viewPoint.z;
  305. if (distance < mCamera->getNearClipDistance()) // Ignore behind clip plane
  306. continue;
  307. if (distance > MAX_ICON_RANGE) // Ignore too far away
  308. continue;
  309. if (!iconData.texture) // Ignore missing texture
  310. continue;
  311. SortedIconData& sortedIconData = mSortedIconData[i];
  312. sortedIconData.iconIdx = i;
  313. sortedIconData.distance = distance;
  314. sortedIconData.screenPosition = mCamera->viewToScreenPoint(viewPoint);
  315. i++;
  316. }
  317. UINT32 actualNumIcons = i;
  318. // Sort back to front first, then by texture
  319. std::sort(mSortedIconData.begin(), mSortedIconData.begin() + actualNumIcons,
  320. [&](const SortedIconData& a, const SortedIconData& b)
  321. {
  322. if (a.distance == b.distance)
  323. {
  324. HSpriteTexture texA = mIconData[a.iconIdx].texture;
  325. HSpriteTexture texB = mIconData[b.iconIdx].texture;
  326. if (texA == texB)
  327. return a.iconIdx < b.iconIdx;
  328. return texA->getInternalID() < texB->getInternalID();
  329. }
  330. else
  331. return a.distance > b.distance;
  332. });
  333. for (i = 0; i < actualNumIcons; i++)
  334. {
  335. }
  336. // TODO - Group by texture
  337. // TODO - Scale icons to always fit in some max size
  338. // TODO - Render in screen space
  339. // TODO - Set up a render method that actually renders the gizmos
  340. // - Optionally also add a special method that renders the gizmos for picking purposes
  341. // ----------------------------
  342. // TODO - In SBansheeEditor:
  343. // - Add BsScriptGizmos that implements the C# Gizmos interface
  344. // - It tracks when an assembly is reloaded, and finds all valid gizmo drawing methods
  345. // - They need to have DrawGizmo attribute and accept a Component of a specific type as first param (and be static)
  346. // - Internally they call GizmoManager
  347. // - Then in update:
  348. // - Call GizmoManager and clear gizmos
  349. // - Go through every SceneObject and their components to find custom gizmos for those types
  350. // - Call their draw gizmo methods
  351. //
  352. // TODO - In ScenePicking:
  353. // - Call GizmoManager that renders all gizmos using picking color coding
  354. // - I might instead just add a way to retrieve render data from GizmoManager since GizmoManager doesn't have access to picking materials
  355. //
  356. // TODO - How do I handle C++ types like Camera and Renderable?
  357. // - Add ComponentBase.cs from which Camera and Renderable inherit
  358. // - Ensure any instances where I currently use Component I use ComponentBase instead (except for actual ManagedComponents)
  359. // - Camera and Renderable will have their own specialized implementation for scripts, but interally I will use normal Camera/Renderable components
  360. // - TODO Haven't thought this out yet
  361. }
  362. }