123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- /*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
- /** \file gameengine/Rasterizer/RAS_BucketManager.cpp
- * \ingroup bgerast
- */
- #ifdef _MSC_VER
- /* don't show these anoying STL warnings */
- # pragma warning (disable:4786)
- #endif
- #include "RAS_MaterialBucket.h"
- #include "RAS_MeshObject.h"
- #include "RAS_Polygon.h"
- #include "RAS_IPolygonMaterial.h"
- #include "RAS_IRasterizer.h"
- #include "RAS_BucketManager.h"
- #include <algorithm>
- /* sorting */
- struct RAS_BucketManager::sortedmeshslot
- {
- public:
- MT_Scalar m_z; /* depth */
- RAS_MeshSlot *m_ms; /* mesh slot */
- RAS_MaterialBucket *m_bucket; /* buck mesh slot came from */
- sortedmeshslot() {}
- void set(RAS_MeshSlot *ms, RAS_MaterialBucket *bucket, const MT_Vector3& pnorm)
- {
- // would be good to use the actual bounding box center instead
- MT_Point3 pos(ms->m_OpenGLMatrix[12], ms->m_OpenGLMatrix[13], ms->m_OpenGLMatrix[14]);
- m_z = MT_dot(pnorm, pos);
- m_ms = ms;
- m_bucket = bucket;
- }
- };
- struct RAS_BucketManager::backtofront
- {
- bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
- {
- return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms);
- }
- };
- struct RAS_BucketManager::fronttoback
- {
- bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
- {
- return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms);
- }
- };
- /* bucket manager */
- RAS_BucketManager::RAS_BucketManager()
- {
- }
- RAS_BucketManager::~RAS_BucketManager()
- {
- BucketList::iterator it;
- for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
- delete (*it);
- for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
- delete(*it);
-
- m_SolidBuckets.clear();
- m_AlphaBuckets.clear();
- }
- void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha)
- {
- BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
- size_t size = 0, i = 0;
- /* Camera's near plane equation: pnorm.dot(point) + pval,
- * but we leave out pval since it's constant anyway */
- const MT_Vector3 pnorm(cameratrans.getBasis()[2]);
- for (bit = buckets.begin(); bit != buckets.end(); ++bit)
- {
- SG_DList::iterator<RAS_MeshSlot> mit((*bit)->GetActiveMeshSlots());
- for (mit.begin(); !mit.end(); ++mit)
- size++;
- }
- slots.resize(size);
- for (bit = buckets.begin(); bit != buckets.end(); ++bit)
- {
- RAS_MaterialBucket* bucket = *bit;
- RAS_MeshSlot* ms;
- // remove the mesh slot from the list, it culls them automatically for next frame
- while ((ms = bucket->GetNextActiveMeshSlot())) {
- slots[i++].set(ms, bucket, pnorm);
- }
- }
-
- if (alpha)
- sort(slots.begin(), slots.end(), backtofront());
- else
- sort(slots.begin(), slots.end(), fronttoback());
- }
- void RAS_BucketManager::RenderAlphaBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
- {
- vector<sortedmeshslot> slots;
- vector<sortedmeshslot>::iterator sit;
- // Having depth masks disabled/enabled gives different artifacts in
- // case no sorting is done or is done inexact. For compatibility, we
- // disable it.
- if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW)
- rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED);
- OrderBuckets(cameratrans, m_AlphaBuckets, slots, true);
-
- for (sit=slots.begin(); sit!=slots.end(); ++sit) {
- rasty->SetClientObject(sit->m_ms->m_clientObj);
- while (sit->m_bucket->ActivateMaterial(cameratrans, rasty))
- sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms));
- // make this mesh slot culled automatically for next frame
- // it will be culled out by frustum culling
- sit->m_ms->SetCulled(true);
- }
- rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
- }
- void RAS_BucketManager::RenderSolidBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
- {
- BucketList::iterator bit;
- rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
- #if 1
- RAS_MaterialBucket* bucket = *bit;
- RAS_MeshSlot* ms;
- // remove the mesh slot from the list, it culls them automatically for next frame
- while ((ms = bucket->GetNextActiveMeshSlot())) {
- rasty->SetClientObject(ms->m_clientObj);
- while (bucket->ActivateMaterial(cameratrans, rasty))
- bucket->RenderMeshSlot(cameratrans, rasty, *ms);
- // make this mesh slot culled automatically for next frame
- // it will be culled out by frustum culling
- ms->SetCulled(true);
- }
- #else
- list<RAS_MeshSlot>::iterator mit;
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- if (mit->IsCulled())
- continue;
- rasty->SetClientObject(rasty, mit->m_clientObj);
- while ((*bit)->ActivateMaterial(cameratrans, rasty))
- (*bit)->RenderMeshSlot(cameratrans, rasty, *mit);
- // make this mesh slot culled automatically for next frame
- // it will be culled out by frustum culling
- mit->SetCulled(true);
- }
- #endif
- }
-
- /* this code draws meshes order front-to-back instead to reduce overdraw.
- * it turned out slower due to much material state switching, a more clever
- * algorithm might do better. */
- #if 0
- vector<sortedmeshslot> slots;
- vector<sortedmeshslot>::iterator sit;
- OrderBuckets(cameratrans, m_SolidBuckets, slots, false);
- for (sit=slots.begin(); sit!=slots.end(); ++sit) {
- rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj);
- while (sit->m_bucket->ActivateMaterial(cameratrans, rasty))
- sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms));
- }
- #endif
- }
- void RAS_BucketManager::Renderbuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty)
- {
- /* beginning each frame, clear (texture/material) caching information */
- rasty->ClearCachingInfo();
- RenderSolidBuckets(cameratrans, rasty);
- RenderAlphaBuckets(cameratrans, rasty);
- /* If we're drawing shadows and bucket wasn't rendered (outside of the lamp frustum or doesn't cast shadows)
- * then the mesh is still modified, so we don't want to set MeshModified to false yet (it will mess up
- * updating display lists). Just leave this step for the main render pass.
- */
- if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW) {
- /* All meshes should be up to date now */
- /* Don't do this while processing buckets because some meshes are split between buckets */
- BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- mit->m_mesh->SetMeshModified(false);
- }
- }
- for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- mit->m_mesh->SetMeshModified(false);
- }
- }
- }
-
- rasty->SetClientObject(NULL);
- }
- RAS_MaterialBucket *RAS_BucketManager::FindBucket(RAS_IPolyMaterial *material, bool &bucketCreated)
- {
- BucketList::iterator it;
- bucketCreated = false;
- for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
- if (*(*it)->GetPolyMaterial() == *material)
- return *it;
-
- for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
- if (*(*it)->GetPolyMaterial() == *material)
- return *it;
-
- RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material);
- bucketCreated = true;
- if (bucket->IsAlpha())
- m_AlphaBuckets.push_back(bucket);
- else
- m_SolidBuckets.push_back(bucket);
-
- return bucket;
- }
- void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance)
- {
- BucketList::iterator bit;
-
- distance = 10.0f;
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit)
- (*bit)->Optimize(distance);
- for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit)
- (*bit)->Optimize(distance);
- }
- void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat)
- {
- BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
- if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- if (mit->m_DisplayList) {
- mit->m_DisplayList->Release();
- mit->m_DisplayList = NULL;
- }
- }
- }
- }
-
- for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
- if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- if (mit->m_DisplayList) {
- mit->m_DisplayList->Release();
- mit->m_DisplayList = NULL;
- }
- }
- }
- }
- }
- void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat)
- {
- BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
- if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
- (*bit)->GetPolyMaterial()->ReleaseMaterial();
- }
- }
-
- for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
- if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
- (*bit)->GetPolyMaterial()->ReleaseMaterial();
- }
- }
- }
- /* frees the bucket, only used when freeing scenes */
- void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat)
- {
- BucketList::iterator bit, bitp;
- list<RAS_MeshSlot>::iterator mit;
- int i;
- for (i=0; i<m_SolidBuckets.size(); i++) {
- RAS_MaterialBucket *bucket = m_SolidBuckets[i];
- if (mat == bucket->GetPolyMaterial()) {
- m_SolidBuckets.erase(m_SolidBuckets.begin()+i);
- delete bucket;
- i--;
- }
- }
- for (int i=0; i<m_AlphaBuckets.size(); i++) {
- RAS_MaterialBucket *bucket = m_AlphaBuckets[i];
- if (mat == bucket->GetPolyMaterial()) {
- m_AlphaBuckets.erase(m_AlphaBuckets.begin()+i);
- delete bucket;
- i--;
- }
- }
- }
- //#include <stdio.h>
- void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene)
- {
- /* concatenate lists */
- // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
- GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() );
- other->GetSolidBuckets().clear();
- GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() );
- other->GetAlphaBuckets().clear();
- //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
- }
|