2
0

CmGUIWidget.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include "CmGUIWidget.h"
  2. #include "CmGUIManager.h"
  3. #include "CmGUISkin.h"
  4. #include "CmGUILabel.h"
  5. #include "CmDeferredRenderContext.h"
  6. #include "CmMaterial.h"
  7. #include "CmPass.h"
  8. #include "CmMesh.h"
  9. namespace CamelotEngine
  10. {
  11. GUISkin GUIWidget::DefaultSkin;
  12. GUIWidget::GUIWidget(const HGameObject& parent)
  13. :Overlay(parent), mSkin(nullptr)
  14. {
  15. GUIManager::instance().registerWidget(this);
  16. }
  17. GUIWidget::~GUIWidget()
  18. {
  19. GUIManager::instance().unregisterWidget(this);
  20. for(auto& elem : mElements)
  21. {
  22. CM_DELETE(elem, GUIElement, GUIAlloc);
  23. }
  24. mElements.clear();
  25. }
  26. GUILabel* GUIWidget::addLabel(const String& text)
  27. {
  28. GUILabel* label = CM_NEW(GUILabel, GUIAlloc) GUILabel(this, text, getGUISkin());
  29. mElements.push_back(label);
  30. return label;
  31. }
  32. void GUIWidget::setSkin(const GUISkin* skin)
  33. {
  34. mSkin = skin;
  35. }
  36. const GUISkin* GUIWidget::getGUISkin() const
  37. {
  38. if(mSkin != nullptr)
  39. return mSkin;
  40. else
  41. return &DefaultSkin;
  42. }
  43. void GUIWidget::updateMeshes() const
  44. {
  45. struct TempMeshData
  46. {
  47. TempMeshData()
  48. :numQuads(0), quadOffset(0), vertices(nullptr),
  49. uvs(nullptr), indices(nullptr)
  50. { }
  51. UINT32 numQuads;
  52. UINT32 quadOffset;
  53. Vector2* vertices;
  54. Vector2* uvs;
  55. UINT32* indices;
  56. HMaterial material;
  57. };
  58. std::unordered_map<UINT64, TempMeshData> meshDataPerRenderElement;
  59. // Group meshes based on used materials
  60. // Determine mesh sizes per group
  61. for(auto& elem : mElements)
  62. {
  63. UINT32 numRenderElems = elem->getNumRenderElements();
  64. for(UINT32 i = 0; i < numRenderElems; i++)
  65. {
  66. const HMaterial& mat = elem->getMaterial(i);
  67. UINT64 meshGroup = mat->getInternalID(); // TODO - I group based on material ID. So if two widgets used exact copies of the same material
  68. // this system won't detect it. Find a better way of determining material similarity?
  69. UINT32 numQuads = elem->getNumQuads(i);
  70. meshDataPerRenderElement[meshGroup].numQuads += numQuads;
  71. meshDataPerRenderElement[meshGroup].material = mat;
  72. }
  73. }
  74. // Allocate buffers for each group
  75. UINT32 numMeshes = 0;
  76. for(auto& renderElem : meshDataPerRenderElement)
  77. {
  78. renderElem.second.vertices = new Vector2[renderElem.second.numQuads * 4];
  79. renderElem.second.uvs = new Vector2[renderElem.second.numQuads * 4];
  80. renderElem.second.indices = new UINT32[renderElem.second.numQuads * 6];
  81. numMeshes++;
  82. }
  83. // Fill buffers for each group
  84. for(auto& elem : mElements)
  85. {
  86. UINT32 numRenderElems = elem->getNumRenderElements();
  87. for(UINT32 i = 0; i < numRenderElems; i++)
  88. {
  89. const HMaterial& mat = elem->getMaterial(i);
  90. UINT64 meshGroup = mat->getInternalID();
  91. Vector2* vertices = meshDataPerRenderElement[meshGroup].vertices;
  92. Vector2* uvs = meshDataPerRenderElement[meshGroup].uvs;
  93. UINT32* indices = meshDataPerRenderElement[meshGroup].indices;
  94. UINT32 startingQuad = meshDataPerRenderElement[meshGroup].quadOffset;
  95. UINT32 maxNumQuads = meshDataPerRenderElement[meshGroup].numQuads;
  96. elem->fillBuffer(vertices, uvs, indices, startingQuad, maxNumQuads, i);
  97. UINT32 numQuads = elem->getNumQuads(i);
  98. meshDataPerRenderElement[meshGroup].quadOffset += numQuads;
  99. }
  100. }
  101. // Update meshes
  102. for(UINT32 i = (UINT32)mCachedMeshes.size(); i < numMeshes; i++)
  103. {
  104. HMesh newMesh = Mesh::create();
  105. mCachedMeshes.push_back(newMesh);
  106. newMesh.waitUntilLoaded();
  107. }
  108. while((UINT32)mCachedMeshes.size() > numMeshes && (UINT32)mCachedMeshes.size() > 0)
  109. {
  110. mCachedMeshes.erase(mCachedMeshes.end() - 1); // TODO: Destroying meshes as soon as they're not used might be a perf. penalty?
  111. // Maybe instead pool the meshes and only actually remove them when a certain number of unused ones exists.
  112. }
  113. mCachedMaterials.resize(numMeshes);
  114. UINT32 meshIdx = 0;
  115. for(auto& renderElem : meshDataPerRenderElement)
  116. {
  117. std::shared_ptr<MeshData> meshData(new MeshData());
  118. meshData->setPositions(renderElem.second.vertices, renderElem.second.numQuads * 4);
  119. meshData->setUV0(renderElem.second.uvs, renderElem.second.numQuads * 4);
  120. meshData->setIndices(renderElem.second.indices, renderElem.second.numQuads * 6);
  121. mCachedMeshes[meshIdx]->setMeshData(meshData);
  122. mCachedMaterials[meshIdx] = renderElem.second.material;
  123. meshIdx++;
  124. }
  125. }
  126. void GUIWidget::render(const CameraPtr& camera, DeferredRenderContextPtr& renderContext) const
  127. {
  128. // Mesh is re-created every frame. There might be a better approach that only recreates it upon change,
  129. // but for now it seems like too much hassle for something like GUI that is pretty dynamic anyway.
  130. updateMeshes();
  131. // Render the meshes
  132. UINT32 meshIdx = 0;
  133. for(auto& mesh : mCachedMeshes)
  134. {
  135. HMaterial material = mCachedMaterials[meshIdx];
  136. if(material == nullptr || !material.isLoaded())
  137. continue;
  138. if(mesh == nullptr || !mesh.isLoaded())
  139. continue;
  140. // TODO - Set current viewport resolution so that GUI can be rendered properly
  141. for(UINT32 i = 0; i < material->getNumPasses(); i++)
  142. {
  143. PassPtr pass = material->getPass(i);
  144. pass->activate(renderContext);
  145. PassParametersPtr paramsPtr = material->getPassParameters(i);
  146. pass->bindParameters(renderContext, paramsPtr);
  147. renderContext->render(mesh->getRenderOperation());
  148. }
  149. meshIdx++;
  150. }
  151. }
  152. }