RAS_BucketManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): none yet.
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. */
  27. /** \file gameengine/Rasterizer/RAS_BucketManager.cpp
  28. * \ingroup bgerast
  29. */
  30. #ifdef _MSC_VER
  31. /* don't show these anoying STL warnings */
  32. # pragma warning (disable:4786)
  33. #endif
  34. #include "RAS_MaterialBucket.h"
  35. #include "RAS_MeshObject.h"
  36. #include "RAS_Polygon.h"
  37. #include "RAS_IPolygonMaterial.h"
  38. #include "RAS_IRasterizer.h"
  39. #include "RAS_BucketManager.h"
  40. #include <algorithm>
  41. /* sorting */
  42. struct RAS_BucketManager::sortedmeshslot
  43. {
  44. public:
  45. MT_Scalar m_z; /* depth */
  46. RAS_MeshSlot *m_ms; /* mesh slot */
  47. RAS_MaterialBucket *m_bucket; /* buck mesh slot came from */
  48. sortedmeshslot() {}
  49. void set(RAS_MeshSlot *ms, RAS_MaterialBucket *bucket, const MT_Vector3& pnorm)
  50. {
  51. // would be good to use the actual bounding box center instead
  52. MT_Point3 pos(ms->m_OpenGLMatrix[12], ms->m_OpenGLMatrix[13], ms->m_OpenGLMatrix[14]);
  53. m_z = MT_dot(pnorm, pos);
  54. m_ms = ms;
  55. m_bucket = bucket;
  56. }
  57. };
  58. struct RAS_BucketManager::backtofront
  59. {
  60. bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
  61. {
  62. return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms);
  63. }
  64. };
  65. struct RAS_BucketManager::fronttoback
  66. {
  67. bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
  68. {
  69. return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms);
  70. }
  71. };
  72. /* bucket manager */
  73. RAS_BucketManager::RAS_BucketManager()
  74. {
  75. }
  76. RAS_BucketManager::~RAS_BucketManager()
  77. {
  78. BucketList::iterator it;
  79. for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
  80. delete (*it);
  81. for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
  82. delete(*it);
  83. m_SolidBuckets.clear();
  84. m_AlphaBuckets.clear();
  85. }
  86. void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha)
  87. {
  88. BucketList::iterator bit;
  89. list<RAS_MeshSlot>::iterator mit;
  90. size_t size = 0, i = 0;
  91. /* Camera's near plane equation: pnorm.dot(point) + pval,
  92. * but we leave out pval since it's constant anyway */
  93. const MT_Vector3 pnorm(cameratrans.getBasis()[2]);
  94. for (bit = buckets.begin(); bit != buckets.end(); ++bit)
  95. {
  96. SG_DList::iterator<RAS_MeshSlot> mit((*bit)->GetActiveMeshSlots());
  97. for (mit.begin(); !mit.end(); ++mit)
  98. size++;
  99. }
  100. slots.resize(size);
  101. for (bit = buckets.begin(); bit != buckets.end(); ++bit)
  102. {
  103. RAS_MaterialBucket* bucket = *bit;
  104. RAS_MeshSlot* ms;
  105. // remove the mesh slot from the list, it culls them automatically for next frame
  106. while ((ms = bucket->GetNextActiveMeshSlot())) {
  107. slots[i++].set(ms, bucket, pnorm);
  108. }
  109. }
  110. if (alpha)
  111. sort(slots.begin(), slots.end(), backtofront());
  112. else
  113. sort(slots.begin(), slots.end(), fronttoback());
  114. }
  115. void RAS_BucketManager::RenderAlphaBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
  116. {
  117. vector<sortedmeshslot> slots;
  118. vector<sortedmeshslot>::iterator sit;
  119. // Having depth masks disabled/enabled gives different artifacts in
  120. // case no sorting is done or is done inexact. For compatibility, we
  121. // disable it.
  122. if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW)
  123. rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED);
  124. OrderBuckets(cameratrans, m_AlphaBuckets, slots, true);
  125. for (sit=slots.begin(); sit!=slots.end(); ++sit) {
  126. rasty->SetClientObject(sit->m_ms->m_clientObj);
  127. while (sit->m_bucket->ActivateMaterial(cameratrans, rasty))
  128. sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms));
  129. // make this mesh slot culled automatically for next frame
  130. // it will be culled out by frustum culling
  131. sit->m_ms->SetCulled(true);
  132. }
  133. rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
  134. }
  135. void RAS_BucketManager::RenderSolidBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
  136. {
  137. BucketList::iterator bit;
  138. rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
  139. for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
  140. #if 1
  141. RAS_MaterialBucket* bucket = *bit;
  142. RAS_MeshSlot* ms;
  143. // remove the mesh slot from the list, it culls them automatically for next frame
  144. while ((ms = bucket->GetNextActiveMeshSlot())) {
  145. rasty->SetClientObject(ms->m_clientObj);
  146. while (bucket->ActivateMaterial(cameratrans, rasty))
  147. bucket->RenderMeshSlot(cameratrans, rasty, *ms);
  148. // make this mesh slot culled automatically for next frame
  149. // it will be culled out by frustum culling
  150. ms->SetCulled(true);
  151. }
  152. #else
  153. list<RAS_MeshSlot>::iterator mit;
  154. for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
  155. if (mit->IsCulled())
  156. continue;
  157. rasty->SetClientObject(rasty, mit->m_clientObj);
  158. while ((*bit)->ActivateMaterial(cameratrans, rasty))
  159. (*bit)->RenderMeshSlot(cameratrans, rasty, *mit);
  160. // make this mesh slot culled automatically for next frame
  161. // it will be culled out by frustum culling
  162. mit->SetCulled(true);
  163. }
  164. #endif
  165. }
  166. /* this code draws meshes order front-to-back instead to reduce overdraw.
  167. * it turned out slower due to much material state switching, a more clever
  168. * algorithm might do better. */
  169. #if 0
  170. vector<sortedmeshslot> slots;
  171. vector<sortedmeshslot>::iterator sit;
  172. OrderBuckets(cameratrans, m_SolidBuckets, slots, false);
  173. for (sit=slots.begin(); sit!=slots.end(); ++sit) {
  174. rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj);
  175. while (sit->m_bucket->ActivateMaterial(cameratrans, rasty))
  176. sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms));
  177. }
  178. #endif
  179. }
  180. void RAS_BucketManager::Renderbuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
  181. {
  182. /* beginning each frame, clear (texture/material) caching information */
  183. rasty->ClearCachingInfo();
  184. RenderSolidBuckets(cameratrans, rasty);
  185. RenderAlphaBuckets(cameratrans, rasty);
  186. /* If we're drawing shadows and bucket wasn't rendered (outside of the lamp frustum or doesn't cast shadows)
  187. * then the mesh is still modified, so we don't want to set MeshModified to false yet (it will mess up
  188. * updating display lists). Just leave this step for the main render pass.
  189. */
  190. if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW) {
  191. /* All meshes should be up to date now */
  192. /* Don't do this while processing buckets because some meshes are split between buckets */
  193. BucketList::iterator bit;
  194. list<RAS_MeshSlot>::iterator mit;
  195. for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
  196. for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
  197. mit->m_mesh->SetMeshModified(false);
  198. }
  199. }
  200. for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
  201. for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
  202. mit->m_mesh->SetMeshModified(false);
  203. }
  204. }
  205. }
  206. rasty->SetClientObject(NULL);
  207. }
  208. RAS_MaterialBucket *RAS_BucketManager::FindBucket(RAS_IPolyMaterial *material, bool &bucketCreated)
  209. {
  210. BucketList::iterator it;
  211. bucketCreated = false;
  212. for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
  213. if (*(*it)->GetPolyMaterial() == *material)
  214. return *it;
  215. for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
  216. if (*(*it)->GetPolyMaterial() == *material)
  217. return *it;
  218. RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material);
  219. bucketCreated = true;
  220. if (bucket->IsAlpha())
  221. m_AlphaBuckets.push_back(bucket);
  222. else
  223. m_SolidBuckets.push_back(bucket);
  224. return bucket;
  225. }
  226. void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance)
  227. {
  228. BucketList::iterator bit;
  229. distance = 10.0f;
  230. for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit)
  231. (*bit)->Optimize(distance);
  232. for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit)
  233. (*bit)->Optimize(distance);
  234. }
  235. void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat)
  236. {
  237. BucketList::iterator bit;
  238. list<RAS_MeshSlot>::iterator mit;
  239. for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
  240. if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
  241. for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
  242. if (mit->m_DisplayList) {
  243. mit->m_DisplayList->Release();
  244. mit->m_DisplayList = NULL;
  245. }
  246. }
  247. }
  248. }
  249. for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
  250. if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
  251. for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
  252. if (mit->m_DisplayList) {
  253. mit->m_DisplayList->Release();
  254. mit->m_DisplayList = NULL;
  255. }
  256. }
  257. }
  258. }
  259. }
  260. void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat)
  261. {
  262. BucketList::iterator bit;
  263. list<RAS_MeshSlot>::iterator mit;
  264. for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
  265. if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
  266. (*bit)->GetPolyMaterial()->ReleaseMaterial();
  267. }
  268. }
  269. for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
  270. if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
  271. (*bit)->GetPolyMaterial()->ReleaseMaterial();
  272. }
  273. }
  274. }
  275. /* frees the bucket, only used when freeing scenes */
  276. void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat)
  277. {
  278. BucketList::iterator bit, bitp;
  279. list<RAS_MeshSlot>::iterator mit;
  280. int i;
  281. for (i=0; i<m_SolidBuckets.size(); i++) {
  282. RAS_MaterialBucket *bucket = m_SolidBuckets[i];
  283. if (mat == bucket->GetPolyMaterial()) {
  284. m_SolidBuckets.erase(m_SolidBuckets.begin()+i);
  285. delete bucket;
  286. i--;
  287. }
  288. }
  289. for (int i=0; i<m_AlphaBuckets.size(); i++) {
  290. RAS_MaterialBucket *bucket = m_AlphaBuckets[i];
  291. if (mat == bucket->GetPolyMaterial()) {
  292. m_AlphaBuckets.erase(m_AlphaBuckets.begin()+i);
  293. delete bucket;
  294. i--;
  295. }
  296. }
  297. }
  298. //#include <stdio.h>
  299. void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene)
  300. {
  301. /* concatenate lists */
  302. // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
  303. GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() );
  304. other->GetSolidBuckets().clear();
  305. GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() );
  306. other->GetAlphaBuckets().clear();
  307. //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
  308. }