BsGizmoManager.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  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. #include "BsCoreThread.h"
  11. #include "BsBuiltinEditorResources.h"
  12. #include "BsMaterial.h"
  13. #include "BsGpuParams.h"
  14. #include "BsRenderSystem.h"
  15. #include "BsRenderer.h"
  16. #include "BsTransientMesh.h"
  17. namespace BansheeEngine
  18. {
  19. const UINT32 GizmoManager::VERTEX_BUFFER_GROWTH = 4096;
  20. const UINT32 GizmoManager::INDEX_BUFFER_GROWTH = 4096 * 2;
  21. const UINT32 GizmoManager::SPHERE_QUALITY = 1;
  22. const float GizmoManager::MAX_ICON_RANGE = 500.0f;
  23. const UINT32 GizmoManager::OPTIMAL_ICON_SIZE = 64;
  24. const float GizmoManager::ICON_TEXEL_WORLD_SIZE = 0.05f;
  25. const float GizmoManager::PICKING_ALPHA_CUTOFF = 0.5f;
  26. GizmoManager::GizmoManager(const HCamera& camera)
  27. :mTotalRequiredSolidIndices(0), mTotalRequiredSolidVertices(0),
  28. mTotalRequiredWireVertices(0), mTotalRequiredWireIndices(0), mCamera(camera), mPickable(false)
  29. {
  30. mSolidVertexDesc = bs_shared_ptr<VertexDataDesc>();
  31. mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  32. mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL);
  33. mSolidVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  34. mWireVertexDesc = bs_shared_ptr<VertexDataDesc>();
  35. mWireVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  36. mWireVertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  37. mIconVertexDesc = bs_shared_ptr<VertexDataDesc>();
  38. mIconVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  39. mIconVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
  40. mIconVertexDesc->addVertElem(VET_COLOR, VES_COLOR, 0);
  41. mIconVertexDesc->addVertElem(VET_COLOR, VES_COLOR, 1);
  42. mSolidMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mSolidVertexDesc);
  43. mWireMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mWireVertexDesc);
  44. mIconMeshHeap = MeshHeap::create(VERTEX_BUFFER_GROWTH, INDEX_BUFFER_GROWTH, mIconVertexDesc);
  45. mSolidMaterial.material = BuiltinEditorResources::instance().createSolidGizmoMat();
  46. mWireMaterial.material = BuiltinEditorResources::instance().createWireGizmoMat();
  47. mIconMaterial.material = BuiltinEditorResources::instance().createIconGizmoMat();
  48. mPickingMaterial.material = BuiltinEditorResources::instance().createGizmoPickingMat();
  49. mAlphaPickingMaterial.material = BuiltinEditorResources::instance().createAlphaGizmoPickingMat();
  50. mSolidMaterial.proxy = mSolidMaterial.material->_createProxy();
  51. mWireMaterial.proxy = mWireMaterial.material->_createProxy();
  52. mIconMaterial.proxy = mIconMaterial.material->_createProxy();
  53. mPickingMaterial.proxy = mPickingMaterial.material->_createProxy();
  54. mAlphaPickingMaterial.proxy = mAlphaPickingMaterial.material->_createProxy();
  55. gCoreAccessor().queueCommand(std::bind(&GizmoManager::initializeCore, this));
  56. }
  57. GizmoManager::~GizmoManager()
  58. {
  59. if (mSolidMesh != nullptr)
  60. mSolidMeshHeap->dealloc(mSolidMesh);
  61. if (mWireMesh != nullptr)
  62. mWireMeshHeap->dealloc(mWireMesh);
  63. if (mIconMesh != nullptr)
  64. mIconMeshHeap->dealloc(mIconMesh);
  65. }
  66. void GizmoManager::initializeCore()
  67. {
  68. THROW_IF_NOT_CORE_THREAD;
  69. // TODO - Make a better interface when dealing with parameters through proxies?
  70. {
  71. MaterialProxyPtr proxy = mWireMaterial.proxy;
  72. GpuParamsPtr vertParams = proxy->params[proxy->passes[0].vertexProgParamsIdx];
  73. vertParams->getParam("matViewProj", mWireMaterial.mViewProj);
  74. }
  75. {
  76. MaterialProxyPtr proxy = mSolidMaterial.proxy;
  77. GpuParamsPtr vertParams = proxy->params[proxy->passes[0].vertexProgParamsIdx];
  78. vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
  79. vertParams->getParam("matViewIT", mSolidMaterial.mViewIT);
  80. }
  81. {
  82. MaterialProxyPtr proxy = mIconMaterial.proxy;
  83. GpuParamsPtr vertParams = proxy->params[proxy->passes[0].vertexProgParamsIdx];
  84. vertParams->getParam("matViewProj", mIconMaterial.mViewProj);
  85. GpuParamsPtr fragParams = proxy->params[proxy->passes[0].fragmentProgParamsIdx];
  86. fragParams->getTextureParam("mainTexture", mIconMaterial.mTexture);
  87. }
  88. {
  89. MaterialProxyPtr proxy = mPickingMaterial.proxy;
  90. GpuParamsPtr vertParams = proxy->params[proxy->passes[0].vertexProgParamsIdx];
  91. vertParams->getParam("matViewProj", mPickingMaterial.mViewProj);
  92. }
  93. {
  94. MaterialProxyPtr proxy = mAlphaPickingMaterial.proxy;
  95. GpuParamsPtr vertParams = proxy->params[proxy->passes[0].vertexProgParamsIdx];
  96. vertParams->getParam("matViewProj", mAlphaPickingMaterial.mViewProj);
  97. GpuParamsPtr fragParams = proxy->params[proxy->passes[0].fragmentProgParamsIdx];
  98. fragParams->getTextureParam("mainTexture", mAlphaPickingMaterial.mTexture);
  99. GpuParamFloat alphaCutoffParam;
  100. fragParams->getParam("alphaCutoff", alphaCutoffParam);
  101. alphaCutoffParam.set(PICKING_ALPHA_CUTOFF);
  102. }
  103. }
  104. void GizmoManager::startGizmo(const HSceneObject& gizmoParent)
  105. {
  106. mActiveSO = gizmoParent;
  107. }
  108. void GizmoManager::endGizmo()
  109. {
  110. mActiveSO = nullptr;
  111. }
  112. void GizmoManager::setColor(const Color& color)
  113. {
  114. mColor = color;
  115. }
  116. void GizmoManager::setTransform(const Matrix4& transform)
  117. {
  118. mTransform = transform;
  119. }
  120. void GizmoManager::drawCube(const Vector3& position, const Vector3& extents)
  121. {
  122. mSolidCubeData.push_back(CubeData());
  123. CubeData& cubeData = mSolidCubeData.back();
  124. cubeData.position = position;
  125. cubeData.extents = extents;
  126. cubeData.color = mColor;
  127. cubeData.transform = mTransform;
  128. cubeData.sceneObject = mActiveSO;
  129. cubeData.pickable = mPickable;
  130. mTotalRequiredSolidVertices += 24;
  131. mTotalRequiredSolidIndices += 36;
  132. }
  133. void GizmoManager::drawSphere(const Vector3& position, float radius)
  134. {
  135. mSolidSphereData.push_back(SphereData());
  136. SphereData& sphereData = mSolidSphereData.back();
  137. sphereData.position = position;
  138. sphereData.radius = radius;
  139. sphereData.color = mColor;
  140. sphereData.transform = mTransform;
  141. sphereData.sceneObject = mActiveSO;
  142. sphereData.pickable = mPickable;
  143. UINT32 numVertices, numIndices;
  144. DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numVertices, numIndices);
  145. mTotalRequiredSolidVertices += numVertices;
  146. mTotalRequiredSolidIndices += numIndices;
  147. }
  148. void GizmoManager::drawWireCube(const Vector3& position, const Vector3& extents)
  149. {
  150. mWireCubeData.push_back(CubeData());
  151. CubeData& cubeData = mWireCubeData.back();
  152. cubeData.position = position;
  153. cubeData.extents = extents;
  154. cubeData.color = mColor;
  155. cubeData.transform = mTransform;
  156. cubeData.sceneObject = mActiveSO;
  157. cubeData.pickable = mPickable;
  158. mTotalRequiredWireVertices += 8;
  159. mTotalRequiredWireIndices += 24;
  160. }
  161. void GizmoManager::drawWireSphere(const Vector3& position, float radius)
  162. {
  163. mWireSphereData.push_back(SphereData());
  164. SphereData& sphereData = mWireSphereData.back();
  165. sphereData.position = position;
  166. sphereData.radius = radius;
  167. sphereData.color = mColor;
  168. sphereData.transform = mTransform;
  169. sphereData.sceneObject = mActiveSO;
  170. sphereData.pickable = mPickable;
  171. UINT32 numVertices, numIndices;
  172. DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numVertices, numIndices);
  173. mTotalRequiredWireVertices += numVertices;
  174. mTotalRequiredWireIndices += numIndices;
  175. }
  176. void GizmoManager::drawLine(const Vector3& start, const Vector3& end)
  177. {
  178. mLineData.push_back(LineData());
  179. LineData& lineData = mLineData.back();
  180. lineData.start = start;
  181. lineData.end = end;
  182. lineData.color = mColor;
  183. lineData.transform = mTransform;
  184. lineData.sceneObject = mActiveSO;
  185. lineData.pickable = mPickable;
  186. mTotalRequiredWireVertices += 2;
  187. mTotalRequiredWireIndices += 2;
  188. }
  189. void GizmoManager::drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far)
  190. {
  191. mFrustumData.push_back(FrustumData());
  192. FrustumData& frustumData = mFrustumData.back();
  193. frustumData.position = position;
  194. frustumData.aspect = aspect;
  195. frustumData.FOV = FOV;
  196. frustumData.near = near;
  197. frustumData.far = far;
  198. frustumData.color = mColor;
  199. frustumData.transform = mTransform;
  200. frustumData.sceneObject = mActiveSO;
  201. frustumData.pickable = mPickable;
  202. mTotalRequiredWireVertices += 8;
  203. mTotalRequiredWireIndices += 36;
  204. }
  205. void GizmoManager::drawIcon(Vector3 position, HSpriteTexture image, bool fixedScale)
  206. {
  207. mIconData.push_back(IconData());
  208. IconData& iconData = mIconData.back();
  209. iconData.position = position;
  210. iconData.texture = image;
  211. iconData.fixedScale = fixedScale;
  212. iconData.color = mColor;
  213. iconData.transform = mTransform;
  214. iconData.sceneObject = mActiveSO;
  215. iconData.pickable = mPickable;
  216. }
  217. void GizmoManager::update()
  218. {
  219. if (mSolidMesh != nullptr)
  220. mSolidMeshHeap->dealloc(mSolidMesh);
  221. if (mWireMesh != nullptr)
  222. mWireMeshHeap->dealloc(mWireMesh);
  223. if (mIconMesh != nullptr)
  224. mIconMeshHeap->dealloc(mIconMesh);
  225. mSolidMesh = buildSolidMesh(mSolidCubeData, mSolidSphereData, mTotalRequiredSolidVertices, mTotalRequiredSolidIndices);
  226. mWireMesh = buildWireMesh(mWireCubeData, mWireSphereData, mLineData, mFrustumData, mTotalRequiredWireVertices, mTotalRequiredWireIndices);
  227. mIconMesh = buildIconMesh(mIconData, false, mIconRenderData);
  228. clearGizmos();
  229. }
  230. void GizmoManager::render()
  231. {
  232. // Note: This must be rendered while Scene view is being rendered
  233. Matrix4 viewMat = mCamera->getViewMatrix();
  234. Matrix4 projMat = mCamera->getProjectionMatrix();
  235. ViewportPtr viewport = mCamera->getViewport();
  236. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderSolidGizmos,
  237. this, viewMat, projMat, mSolidMesh->_createProxy(0)));
  238. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderWireGizmos,
  239. this, viewMat, projMat, mWireMesh->_createProxy(0)));
  240. RectI screenArea = mCamera->getViewport()->getArea();
  241. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderIconGizmos,
  242. this, screenArea, mIconMesh->_createProxy(0), mIconRenderData));
  243. }
  244. void GizmoManager::renderForPicking(std::function<Color(UINT32)> idxToColorCallback)
  245. {
  246. Vector<CubeData> solidCubeData = mSolidCubeData;
  247. Vector<CubeData> wireCubeData = mWireCubeData;
  248. Vector<SphereData> solidSphereData = mSolidSphereData;
  249. Vector<SphereData> wireSphereData = mWireSphereData;
  250. Vector<LineData> lineData = mLineData;
  251. Vector<FrustumData> frustumData = mFrustumData;
  252. Vector<IconData> iconData = mIconData;
  253. IconRenderDataVecPtr iconRenderData;
  254. UINT32 gizmoIdx = 0; // TODO - Since I need to be able to quickly access gizmo data per ID i'll probably want to assign this when they're initially added and used an unordered map
  255. for (auto& cubeDataEntry : solidCubeData)
  256. cubeDataEntry.color = idxToColorCallback(gizmoIdx++);
  257. for (auto& cubeDataEntry : wireCubeData)
  258. cubeDataEntry.color = idxToColorCallback(gizmoIdx++);
  259. for (auto& sphereDataEntry : solidSphereData)
  260. sphereDataEntry.color = idxToColorCallback(gizmoIdx++);
  261. for (auto& sphereDataEntry : wireSphereData)
  262. sphereDataEntry.color = idxToColorCallback(gizmoIdx++);
  263. for (auto& lineDataEntry : lineData)
  264. lineDataEntry.color = idxToColorCallback(gizmoIdx++);
  265. for (auto& iconDataEntry : iconData)
  266. iconDataEntry.color = idxToColorCallback(gizmoIdx++);
  267. TransientMeshPtr solidMesh = buildSolidMesh(solidCubeData, solidSphereData, mTotalRequiredSolidVertices, mTotalRequiredSolidIndices);
  268. TransientMeshPtr wireMesh = buildWireMesh(wireCubeData, wireSphereData, lineData, frustumData, mTotalRequiredWireVertices, mTotalRequiredWireIndices);
  269. TransientMeshPtr iconMesh = buildIconMesh(iconData, true, iconRenderData);
  270. // Note: This must be rendered while Scene view is being rendered
  271. Matrix4 viewMat = mCamera->getViewMatrix();
  272. Matrix4 projMat = mCamera->getProjectionMatrix();
  273. ViewportPtr viewport = mCamera->getViewport();
  274. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderGizmosForPicking,
  275. this, viewMat, projMat, solidMesh->_createProxy(0)));
  276. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderGizmosForPicking,
  277. this, viewMat, projMat, wireMesh->_createProxy(0)));
  278. RectI screenArea = mCamera->getViewport()->getArea();
  279. gCoreAccessor().queueCommand(std::bind(&GizmoManager::coreRenderIconGizmosForPicking,
  280. this, screenArea, iconMesh->_createProxy(0), iconRenderData));
  281. if (solidMesh != nullptr)
  282. mSolidMeshHeap->dealloc(solidMesh);
  283. if (wireMesh != nullptr)
  284. mWireMeshHeap->dealloc(wireMesh);
  285. if (iconMesh != nullptr)
  286. mIconMeshHeap->dealloc(iconMesh);
  287. }
  288. void GizmoManager::clearGizmos()
  289. {
  290. mSolidCubeData.clear();
  291. mWireCubeData.clear();
  292. mSolidSphereData.clear();
  293. mWireSphereData.clear();
  294. mLineData.clear();
  295. mFrustumData.clear();
  296. mIconData.clear();
  297. mTotalRequiredSolidVertices = 0;
  298. mTotalRequiredSolidIndices = 0;
  299. mTotalRequiredWireVertices = 0;
  300. mTotalRequiredWireIndices = 0;
  301. }
  302. TransientMeshPtr GizmoManager::buildSolidMesh(const Vector<CubeData>& cubeData, const Vector<SphereData>& sphereData,
  303. UINT32 numVertices, UINT32 numIndices)
  304. {
  305. MeshDataPtr meshData = bs_shared_ptr<MeshData>(numVertices, numIndices, mSolidVertexDesc);
  306. UINT32 curVertexOffset = 0;
  307. UINT32 curIndexOffet = 0;
  308. auto positionIter = meshData->getVec3DataIter(VES_POSITION);
  309. auto normalIter = meshData->getVec3DataIter(VES_NORMAL);
  310. auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
  311. for (auto& cubeData : cubeData)
  312. {
  313. AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
  314. DrawHelper3D::instance().solidAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
  315. Matrix4 transformIT = cubeData.transform.inverseAffine().transpose();
  316. RGBA color = cubeData.color.getAsRGBA();
  317. UINT32 numVertices = 24;
  318. for (UINT32 i = 0; i < numVertices; i++)
  319. {
  320. Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
  321. Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
  322. positionIter.addValue(worldPos);
  323. normalIter.addValue(worldNormal);
  324. colorIter.addValue(color);
  325. }
  326. curVertexOffset += numVertices;
  327. curIndexOffet += 36;
  328. }
  329. UINT32 numSphereVertices, numSphereIndices;
  330. DrawHelper3D::getNumElementsSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
  331. for (auto& sphereData : sphereData)
  332. {
  333. Sphere sphere(sphereData.position, sphereData.radius);
  334. DrawHelper3D::instance().solidSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
  335. Matrix4 transformIT = sphereData.transform.inverseAffine().transpose();
  336. RGBA color = sphereData.color.getAsRGBA();
  337. for (UINT32 i = 0; i < numSphereVertices; i++)
  338. {
  339. Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
  340. Vector3 worldNormal = transformIT.multiply3x4(normalIter.getValue());
  341. positionIter.addValue(worldPos);
  342. normalIter.addValue(worldNormal);
  343. colorIter.addValue(color);
  344. }
  345. curVertexOffset += numSphereVertices;
  346. curIndexOffet += numSphereIndices;
  347. }
  348. return mSolidMeshHeap->alloc(meshData, DOT_TRIANGLE_LIST);
  349. }
  350. TransientMeshPtr GizmoManager::buildWireMesh(const Vector<CubeData>& cubeData, const Vector<SphereData>& sphereData,
  351. const Vector<LineData>& lineData, const Vector<FrustumData>& frustumData, UINT32 numVertices, UINT32 numIndices)
  352. {
  353. MeshDataPtr meshData = bs_shared_ptr<MeshData>(numVertices, numIndices, mWireVertexDesc);
  354. UINT32 curVertexOffset = 0;
  355. UINT32 curIndexOffet = 0;
  356. auto positionIter = meshData->getVec3DataIter(VES_POSITION);
  357. auto colorIter = meshData->getDWORDDataIter(VES_COLOR);
  358. for (auto& cubeData : cubeData)
  359. {
  360. AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents);
  361. DrawHelper3D::instance().wireAABox(box, meshData, curVertexOffset, curIndexOffet); // TODO - These should be static methods
  362. RGBA color = cubeData.color.getAsRGBA();
  363. UINT32 numVertices = 8;
  364. for (UINT32 i = 0; i < numVertices; i++)
  365. {
  366. Vector3 worldPos = cubeData.transform.multiply3x4(positionIter.getValue());
  367. positionIter.addValue(worldPos);
  368. colorIter.addValue(color);
  369. }
  370. curVertexOffset += numVertices;
  371. curIndexOffet += 24;
  372. }
  373. UINT32 numSphereVertices, numSphereIndices;
  374. DrawHelper3D::getNumElementsWireSphere(SPHERE_QUALITY, numSphereVertices, numSphereIndices);
  375. for (auto& sphereData : sphereData)
  376. {
  377. Sphere sphere(sphereData.position, sphereData.radius);
  378. DrawHelper3D::instance().wireSphere(sphere, meshData, curVertexOffset, curIndexOffet, SPHERE_QUALITY);
  379. RGBA color = sphereData.color.getAsRGBA();
  380. for (UINT32 i = 0; i < numSphereVertices; i++)
  381. {
  382. Vector3 worldPos = sphereData.transform.multiply3x4(positionIter.getValue());
  383. positionIter.addValue(worldPos);
  384. colorIter.addValue(color);
  385. }
  386. curVertexOffset += numSphereVertices;
  387. curIndexOffet += numSphereIndices;
  388. }
  389. for (auto& lineData : lineData)
  390. {
  391. DrawHelper3D::instance().pixelLine(lineData.start, lineData.end, meshData, curVertexOffset, curIndexOffet);
  392. RGBA color = lineData.color.getAsRGBA();
  393. for (UINT32 i = 0; i < 2; i++)
  394. {
  395. Vector3 worldPos = lineData.transform.multiply3x4(positionIter.getValue());
  396. positionIter.addValue(worldPos);
  397. colorIter.addValue(color);
  398. }
  399. curVertexOffset += 2;
  400. curIndexOffet += 2;
  401. }
  402. for (auto& frustumData : frustumData)
  403. {
  404. DrawHelper3D::instance().wireFrustum(frustumData.aspect, frustumData.FOV, frustumData.near,
  405. frustumData.far, meshData, curVertexOffset, curIndexOffet);
  406. RGBA color = frustumData.color.getAsRGBA();
  407. for (UINT32 i = 0; i < 8; i++)
  408. {
  409. Vector3 worldPos = frustumData.transform.multiply3x4(positionIter.getValue());
  410. positionIter.addValue(worldPos);
  411. colorIter.addValue(color);
  412. }
  413. curVertexOffset += 8;
  414. curIndexOffet += 24;
  415. }
  416. return mWireMeshHeap->alloc(meshData, DOT_LINE_LIST);
  417. }
  418. TransientMeshPtr GizmoManager::buildIconMesh(const Vector<IconData>& iconData, bool pickingOnly, GizmoManager::IconRenderDataVecPtr& iconRenderData)
  419. {
  420. mSortedIconData.clear();
  421. if (iconData.size() > mSortedIconData.size())
  422. mSortedIconData.resize(iconData.size());
  423. UINT32 i = 0;
  424. for (auto& iconData : mIconData)
  425. {
  426. Vector3 viewPoint = mCamera->worldToViewPoint(iconData.position);
  427. float distance = -viewPoint.z;
  428. if (distance < mCamera->getNearClipDistance()) // Ignore behind clip plane
  429. continue;
  430. if (distance > MAX_ICON_RANGE) // Ignore too far away
  431. continue;
  432. if (!iconData.texture) // Ignore missing texture
  433. continue;
  434. if (pickingOnly && !iconData.pickable)
  435. continue;
  436. SortedIconData& sortedIconData = mSortedIconData[i];
  437. sortedIconData.iconIdx = i;
  438. sortedIconData.distance = distance;
  439. sortedIconData.screenPosition = mCamera->viewToScreenPoint(viewPoint);
  440. i++;
  441. }
  442. UINT32 actualNumIcons = i;
  443. // Sort back to front first, then by texture
  444. std::sort(mSortedIconData.begin(), mSortedIconData.begin() + actualNumIcons,
  445. [&](const SortedIconData& a, const SortedIconData& b)
  446. {
  447. if (a.distance == b.distance)
  448. {
  449. HSpriteTexture texA = iconData[a.iconIdx].texture->getTexture();
  450. HSpriteTexture texB = iconData[b.iconIdx].texture->getTexture();
  451. if (texA == texB)
  452. return a.iconIdx < b.iconIdx;
  453. return texA->getInternalID() < texB->getInternalID();
  454. }
  455. else
  456. return a.distance > b.distance;
  457. });
  458. MeshDataPtr meshData = bs_shared_ptr<MeshData>(actualNumIcons * 4, actualNumIcons * 6, mIconVertexDesc);
  459. auto positionIter = meshData->getVec3DataIter(VES_POSITION);
  460. auto texcoordIter = meshData->getVec2DataIter(VES_TEXCOORD);
  461. auto normalColorIter = meshData->getDWORDDataIter(VES_COLOR, 0);
  462. auto fadedColorIter = meshData->getDWORDDataIter(VES_COLOR, 1);
  463. UINT32* indices = meshData->getIndices32();
  464. float cameraScale = 1.0f;
  465. if (mCamera->getProjectionType() == PT_ORTHOGRAPHIC)
  466. cameraScale = mCamera->getViewport()->getHeight() / mCamera->getOrthoWindowHeight();
  467. else
  468. {
  469. Radian vertFOV(Math::tan(mCamera->getHorzFOV() * 0.5f));
  470. cameraScale = (mCamera->getViewport()->getHeight() * 0.5f) / vertFOV.valueRadians();
  471. }
  472. iconRenderData = bs_shared_ptr<IconRenderDataVec>();
  473. UINT32 lastTextureIdx = 0;
  474. HTexture curTexture;
  475. // Note: This assumes the meshes will be rendered using the same camera
  476. // properties as when they are created
  477. for (i = 0; i < actualNumIcons; i++)
  478. {
  479. SortedIconData& sortedIconData = mSortedIconData[i];
  480. const IconData& curIconData = iconData[sortedIconData.iconIdx];
  481. if (curTexture != curIconData.texture)
  482. {
  483. UINT32 numIconsPerTexture = i - lastTextureIdx;
  484. if (numIconsPerTexture > 0)
  485. {
  486. iconRenderData->push_back(IconRenderData());
  487. IconRenderData& renderData = iconRenderData->back();
  488. renderData.count = numIconsPerTexture;
  489. renderData.texture = curTexture;
  490. }
  491. lastTextureIdx = i;
  492. curTexture = curIconData.texture;
  493. }
  494. UINT32 iconWidth = curIconData.texture->getWidth();
  495. UINT32 iconHeight = curIconData.texture->getHeight();
  496. limitIconSize(iconWidth, iconHeight);
  497. Color normalColor, fadedColor;
  498. calculateIconColors(curIconData.color, *mCamera.get(), iconHeight, curIconData.fixedScale, normalColor, fadedColor);
  499. Vector3 position((float)sortedIconData.screenPosition.x, (float)sortedIconData.screenPosition.y, sortedIconData.distance);
  500. // TODO - Does the depth need to be corrected since it was taken from a projective camera (probably)?
  501. float halfWidth = iconWidth * 0.5f;
  502. float halfHeight = iconHeight * 0.5f;
  503. if (!curIconData.fixedScale)
  504. {
  505. float iconScale = 1.0f;
  506. if (mCamera->getProjectionType() == PT_ORTHOGRAPHIC)
  507. iconScale = cameraScale;
  508. else
  509. iconScale = cameraScale / sortedIconData.distance;
  510. halfWidth *= iconScale;
  511. halfHeight *= iconScale;
  512. }
  513. Vector3 positions[4];
  514. positions[0] = position + Vector3(-halfWidth, -halfHeight, 0.0f);
  515. positions[1] = position + Vector3(halfWidth, -halfHeight, 0.0f);
  516. positions[2] = position + Vector3(-halfWidth, halfHeight, 0.0f);
  517. positions[3] = position + Vector3(halfWidth, halfHeight, 0.0f);
  518. Vector2 uvs[4];
  519. uvs[0] = curIconData.texture->transformUV(Vector2(0.0f, 0.0f));
  520. uvs[1] = curIconData.texture->transformUV(Vector2(1.0f, 0.0f));
  521. uvs[2] = curIconData.texture->transformUV(Vector2(0.0f, 1.0f));
  522. uvs[3] = curIconData.texture->transformUV(Vector2(1.0f, 1.0f));
  523. for (UINT32 j = 0; j < 4; j++)
  524. {
  525. positionIter.addValue(positions[j]);
  526. texcoordIter.addValue(uvs[j]);
  527. normalColorIter.addValue(normalColor.getAsRGBA());
  528. fadedColorIter.addValue(fadedColor.getAsRGBA());
  529. }
  530. UINT32 vertOffset = i * 4;
  531. indices[0] = vertOffset + 0;
  532. indices[1] = vertOffset + 1;
  533. indices[2] = vertOffset + 2;
  534. indices[3] = vertOffset + 1;
  535. indices[4] = vertOffset + 3;
  536. indices[5] = vertOffset + 2;
  537. indices += 6;
  538. }
  539. return mIconMeshHeap->alloc(meshData, DOT_TRIANGLE_LIST);
  540. }
  541. void GizmoManager::limitIconSize(UINT32& width, UINT32& height)
  542. {
  543. if (width <= OPTIMAL_ICON_SIZE && height <= OPTIMAL_ICON_SIZE)
  544. return;
  545. float relWidth = OPTIMAL_ICON_SIZE / (float)width;
  546. float relHeight = OPTIMAL_ICON_SIZE / (float)height;
  547. float scale = std::min(relWidth, relHeight);
  548. width = Math::roundToInt(width * scale);
  549. height = Math::roundToInt(height * scale);
  550. }
  551. void GizmoManager::calculateIconColors(const Color& tint, const Camera& camera,
  552. UINT32 iconHeight, bool fixedScale, Color& normalColor, Color& fadedColor)
  553. {
  554. normalColor = tint;
  555. if (!fixedScale)
  556. {
  557. float iconToScreenRatio = iconHeight / (float)camera.getViewport()->getHeight();
  558. if (iconToScreenRatio > 0.3f)
  559. {
  560. float alpha = 1.0f - Math::lerp01(iconToScreenRatio, 0.3f, 1.0f);
  561. normalColor.a *= alpha;
  562. }
  563. else if (iconToScreenRatio < 0.1f)
  564. {
  565. float alpha = Math::lerp01(iconToScreenRatio, 0.0f, 0.1f);
  566. normalColor.a *= alpha;
  567. }
  568. }
  569. fadedColor = normalColor;
  570. fadedColor.a *= 0.2f;
  571. }
  572. void GizmoManager::coreRenderSolidGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr meshProxy)
  573. {
  574. THROW_IF_NOT_CORE_THREAD;
  575. Matrix4 viewProjMat = projMatrix * viewMatrix;
  576. Matrix4 viewIT = viewMatrix.inverse().transpose();
  577. mSolidMaterial.mViewProj.set(viewProjMat);
  578. mSolidMaterial.mViewIT.set(viewIT);
  579. Renderer::setPass(*mSolidMaterial.proxy, 0);
  580. Renderer::draw(*meshProxy);
  581. }
  582. void GizmoManager::coreRenderWireGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr meshProxy)
  583. {
  584. THROW_IF_NOT_CORE_THREAD;
  585. Matrix4 viewProjMat = projMatrix * viewMatrix;
  586. Matrix4 viewIT = viewMatrix.inverse().transpose();
  587. mWireMaterial.mViewProj.set(viewProjMat);
  588. Renderer::setPass(*mWireMaterial.proxy, 0);
  589. Renderer::draw(*meshProxy);
  590. }
  591. void GizmoManager::coreRenderIconGizmos(RectI screenArea, MeshProxyPtr meshProxy, IconRenderDataVecPtr renderData)
  592. {
  593. RenderSystem& rs = RenderSystem::instance();
  594. MeshBasePtr mesh;
  595. // TODO: Instead of this lock consider just storing all needed data in MeshProxy and not referencing Mesh at all?
  596. if (!meshProxy->mesh.expired())
  597. mesh = meshProxy->mesh.lock();
  598. else
  599. return;
  600. std::shared_ptr<VertexData> vertexData = mesh->_getVertexData();
  601. rs.setVertexDeclaration(vertexData->vertexDeclaration);
  602. auto vertexBuffers = vertexData->getBuffers();
  603. VertexBufferPtr vertBuffers[1] = { vertexBuffers.begin()->second };
  604. rs.setVertexBuffers(0, vertBuffers, 1);
  605. IndexBufferPtr indexBuffer = mesh->_getIndexBuffer();
  606. rs.setIndexBuffer(indexBuffer);
  607. rs.setDrawOperation(DOT_TRIANGLE_LIST);
  608. // Set up ortho matrix
  609. Matrix4 projMat;
  610. float left = screenArea.x + rs.getHorizontalTexelOffset();
  611. float right = screenArea.x + screenArea.width + rs.getHorizontalTexelOffset();
  612. float top = screenArea.y + rs.getVerticalTexelOffset();
  613. float bottom = screenArea.y + screenArea.height + rs.getVerticalTexelOffset();
  614. float near = rs.getMinimumDepthInputValue();
  615. float far = rs.getMaximumDepthInputValue();
  616. projMat.makeProjectionOrtho(left, right, top, bottom, near, far);
  617. mIconMaterial.mViewProj.set(projMat);
  618. for (UINT32 passIdx = 0; passIdx < 2; passIdx++)
  619. {
  620. Renderer::setPass(*mIconMaterial.proxy, passIdx);
  621. UINT32 curIndexOffset = 0;
  622. for (auto curRenderData : *renderData)
  623. {
  624. mIconMaterial.mTexture.set(curRenderData.texture);
  625. rs.drawIndexed(curIndexOffset, curRenderData.count * 6, 0, curRenderData.count * 4);
  626. curIndexOffset += curRenderData.count * 6;
  627. }
  628. }
  629. mesh->_notifyUsedOnGPU();
  630. }
  631. void GizmoManager::coreRenderGizmosForPicking(Matrix4 viewMatrix, Matrix4 projMatrix, MeshProxyPtr meshProxy)
  632. {
  633. THROW_IF_NOT_CORE_THREAD;
  634. Matrix4 viewProjMat = projMatrix * viewMatrix;
  635. mSolidMaterial.mViewProj.set(viewProjMat);
  636. Renderer::setPass(*mPickingMaterial.proxy, 0);
  637. Renderer::draw(*meshProxy);
  638. }
  639. void GizmoManager::coreRenderIconGizmosForPicking(RectI screenArea, MeshProxyPtr meshProxy, IconRenderDataVecPtr renderData)
  640. {
  641. RenderSystem& rs = RenderSystem::instance();
  642. MeshBasePtr mesh;
  643. // TODO: Instead of this lock consider just storing all needed data in MeshProxy and not referencing Mesh at all?
  644. if (!meshProxy->mesh.expired())
  645. mesh = meshProxy->mesh.lock();
  646. else
  647. return;
  648. std::shared_ptr<VertexData> vertexData = mesh->_getVertexData();
  649. rs.setVertexDeclaration(vertexData->vertexDeclaration);
  650. auto vertexBuffers = vertexData->getBuffers();
  651. VertexBufferPtr vertBuffers[1] = { vertexBuffers.begin()->second };
  652. rs.setVertexBuffers(0, vertBuffers, 1);
  653. IndexBufferPtr indexBuffer = mesh->_getIndexBuffer();
  654. rs.setIndexBuffer(indexBuffer);
  655. rs.setDrawOperation(DOT_TRIANGLE_LIST);
  656. // Set up ortho matrix
  657. Matrix4 projMat;
  658. float left = screenArea.x + rs.getHorizontalTexelOffset();
  659. float right = screenArea.x + screenArea.width + rs.getHorizontalTexelOffset();
  660. float top = screenArea.y + rs.getVerticalTexelOffset();
  661. float bottom = screenArea.y + screenArea.height + rs.getVerticalTexelOffset();
  662. float near = rs.getMinimumDepthInputValue();
  663. float far = rs.getMaximumDepthInputValue();
  664. projMat.makeProjectionOrtho(left, right, top, bottom, near, far);
  665. mAlphaPickingMaterial.mViewProj.set(projMat);
  666. Renderer::setPass(*mAlphaPickingMaterial.proxy, 0);
  667. UINT32 curIndexOffset = 0;
  668. for (auto curRenderData : *renderData)
  669. {
  670. mAlphaPickingMaterial.mTexture.set(curRenderData.texture);
  671. rs.drawIndexed(curIndexOffset, curRenderData.count * 6, 0, curRenderData.count * 4);
  672. curIndexOffset += curRenderData.count * 6;
  673. }
  674. mesh->_notifyUsedOnGPU();
  675. }
  676. }