Blender  V2.59
RAS_BucketManager.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: RAS_BucketManager.cpp 36523 2011-05-06 20:18:42Z blendix $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #if defined(WIN32) && !defined(FREE_WINDOWS)
00035 // don't show these anoying STL warnings
00036 #pragma warning (disable:4786)
00037 #endif
00038 
00039 #include "CTR_Map.h"
00040 #include "RAS_MaterialBucket.h"
00041 #include "STR_HashedString.h"
00042 #include "RAS_MeshObject.h"
00043 #include "RAS_IRasterizer.h"
00044 #include "RAS_IRenderTools.h"
00045 
00046 #include "RAS_BucketManager.h"
00047 
00048 #include <algorithm>
00049 #include <set>
00050 
00051 /* sorting */
00052 
00053 struct RAS_BucketManager::sortedmeshslot
00054 {
00055 public:
00056         MT_Scalar m_z;                                  /* depth */
00057         RAS_MeshSlot *m_ms;                             /* mesh slot */
00058         RAS_MaterialBucket *m_bucket;   /* buck mesh slot came from */
00059 
00060         sortedmeshslot() {}
00061 
00062         void set(RAS_MeshSlot *ms, RAS_MaterialBucket *bucket, const MT_Vector3& pnorm)
00063         {
00064                 // would be good to use the actual bounding box center instead
00065                 MT_Point3 pos(ms->m_OpenGLMatrix[12], ms->m_OpenGLMatrix[13], ms->m_OpenGLMatrix[14]);
00066 
00067                 m_z = MT_dot(pnorm, pos);
00068                 m_ms = ms;
00069                 m_bucket = bucket;
00070         }
00071 };
00072 
00073 struct RAS_BucketManager::backtofront
00074 {
00075         bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
00076         {
00077                 return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms);
00078         }
00079 };
00080 
00081 struct RAS_BucketManager::fronttoback
00082 {
00083         bool operator()(const sortedmeshslot &a, const sortedmeshslot &b)
00084         {
00085                 return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms);
00086         }
00087 };
00088 
00089 /* bucket manager */
00090 
00091 RAS_BucketManager::RAS_BucketManager()
00092 {
00093 
00094 }
00095 
00096 RAS_BucketManager::~RAS_BucketManager()
00097 {
00098         BucketList::iterator it;
00099 
00100         for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
00101                 delete (*it);
00102 
00103         for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
00104                 delete(*it);
00105         
00106         m_SolidBuckets.clear();
00107         m_AlphaBuckets.clear();
00108 }
00109 
00110 void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha)
00111 {
00112         BucketList::iterator bit;
00113         list<RAS_MeshSlot>::iterator mit;
00114         size_t size = 0, i = 0;
00115 
00116         /* Camera's near plane equation: pnorm.dot(point) + pval,
00117          * but we leave out pval since it's constant anyway */
00118         const MT_Vector3 pnorm(cameratrans.getBasis()[2]);
00119 
00120         for (bit = buckets.begin(); bit != buckets.end(); ++bit)
00121         {
00122                 SG_DList::iterator<RAS_MeshSlot> mit((*bit)->GetActiveMeshSlots());
00123                 for(mit.begin(); !mit.end(); ++mit)
00124                         size++;
00125         }
00126 
00127         slots.resize(size);
00128 
00129         for (bit = buckets.begin(); bit != buckets.end(); ++bit)
00130         {
00131                 RAS_MaterialBucket* bucket = *bit;
00132                 RAS_MeshSlot* ms;
00133                 // remove the mesh slot form the list, it culls them automatically for next frame
00134                 while((ms = bucket->GetNextActiveMeshSlot())) {
00135                         slots[i++].set(ms, bucket, pnorm);
00136                 }
00137         }
00138                 
00139         if(alpha)
00140                 sort(slots.begin(), slots.end(), backtofront());
00141         else
00142                 sort(slots.begin(), slots.end(), fronttoback());
00143 }
00144 
00145 void RAS_BucketManager::RenderAlphaBuckets(
00146         const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
00147 {
00148         vector<sortedmeshslot> slots;
00149         vector<sortedmeshslot>::iterator sit;
00150 
00151         // Having depth masks disabled/enabled gives different artifacts in
00152         // case no sorting is done or is done inexact. For compatibility, we
00153         // disable it.
00154         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED);
00155 
00156         OrderBuckets(cameratrans, m_AlphaBuckets, slots, true);
00157         
00158         for(sit=slots.begin(); sit!=slots.end(); ++sit) {
00159                 rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj);
00160 
00161                 while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools))
00162                         sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms));
00163 
00164                 // make this mesh slot culled automatically for next frame
00165                 // it will be culled out by frustrum culling
00166                 sit->m_ms->SetCulled(true);
00167         }
00168 
00169         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
00170 }
00171 
00172 void RAS_BucketManager::RenderSolidBuckets(
00173         const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
00174 {
00175         BucketList::iterator bit;
00176 
00177         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
00178 
00179         for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
00180 #if 1
00181                 RAS_MaterialBucket* bucket = *bit;
00182                 RAS_MeshSlot* ms;
00183                 // remove the mesh slot form the list, it culls them automatically for next frame
00184                 while((ms = bucket->GetNextActiveMeshSlot()))
00185                 {
00186                         rendertools->SetClientObject(rasty, ms->m_clientObj);
00187                         while (bucket->ActivateMaterial(cameratrans, rasty, rendertools))
00188                                 bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *ms);
00189 
00190                         // make this mesh slot culled automatically for next frame
00191                         // it will be culled out by frustrum culling
00192                         ms->SetCulled(true);
00193                 }
00194 #else
00195                 list<RAS_MeshSlot>::iterator mit;
00196                 for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
00197                         if (mit->IsCulled())
00198                                 continue;
00199 
00200                         rendertools->SetClientObject(rasty, mit->m_clientObj);
00201 
00202                         while ((*bit)->ActivateMaterial(cameratrans, rasty, rendertools))
00203                                 (*bit)->RenderMeshSlot(cameratrans, rasty, rendertools, *mit);
00204 
00205                         // make this mesh slot culled automatically for next frame
00206                         // it will be culled out by frustrum culling
00207                         mit->SetCulled(true);
00208                 }
00209 #endif
00210         }
00211         
00212         /* this code draws meshes order front-to-back instead to reduce overdraw.
00213          * it turned out slower due to much material state switching, a more clever
00214          * algorithm might do better. */
00215 #if 0
00216         vector<sortedmeshslot> slots;
00217         vector<sortedmeshslot>::iterator sit;
00218 
00219         OrderBuckets(cameratrans, m_SolidBuckets, slots, false);
00220 
00221         for(sit=slots.begin(); sit!=slots.end(); ++sit) {
00222                 rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj);
00223 
00224                 while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools))
00225                         sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms));
00226         }
00227 #endif
00228 }
00229 
00230 void RAS_BucketManager::Renderbuckets(
00231         const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
00232 {
00233         /* beginning each frame, clear (texture/material) caching information */
00234         rasty->ClearCachingInfo();
00235 
00236         RenderSolidBuckets(cameratrans, rasty, rendertools);    
00237         RenderAlphaBuckets(cameratrans, rasty, rendertools);    
00238 
00239         rendertools->SetClientObject(rasty, NULL);
00240 }
00241 
00242 RAS_MaterialBucket* RAS_BucketManager::FindBucket(RAS_IPolyMaterial * material, bool &bucketCreated)
00243 {
00244         BucketList::iterator it;
00245 
00246         bucketCreated = false;
00247 
00248         for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++)
00249                 if (*(*it)->GetPolyMaterial() == *material)
00250                         return *it;
00251         
00252         for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
00253                 if (*(*it)->GetPolyMaterial() == *material)
00254                         return *it;
00255         
00256         RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material);
00257         bucketCreated = true;
00258 
00259         if (bucket->IsAlpha())
00260                 m_AlphaBuckets.push_back(bucket);
00261         else
00262                 m_SolidBuckets.push_back(bucket);
00263         
00264         return bucket;
00265 }
00266 
00267 void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance)
00268 {
00269         BucketList::iterator bit;
00270         
00271         distance = 10.0;
00272 
00273         for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit)
00274                 (*bit)->Optimize(distance);
00275         for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit)
00276                 (*bit)->Optimize(distance);
00277 }
00278 
00279 void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat)
00280 {
00281         BucketList::iterator bit;
00282         list<RAS_MeshSlot>::iterator mit;
00283 
00284         for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
00285                 if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
00286                         for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
00287                                 if(mit->m_DisplayList) {
00288                                         mit->m_DisplayList->Release();
00289                                         mit->m_DisplayList = NULL;
00290                                 }
00291                         }
00292                 }
00293         }
00294         
00295         for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
00296                 if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
00297                         for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
00298                                 if(mit->m_DisplayList) {
00299                                         mit->m_DisplayList->Release();
00300                                         mit->m_DisplayList = NULL;
00301                                 }
00302                         }
00303                 }
00304         }
00305 }
00306 
00307 void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat)
00308 {
00309         BucketList::iterator bit;
00310         list<RAS_MeshSlot>::iterator mit;
00311 
00312         for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
00313                 if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
00314                         (*bit)->GetPolyMaterial()->ReleaseMaterial();
00315                 }
00316         }
00317         
00318         for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
00319                 if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
00320                         (*bit)->GetPolyMaterial()->ReleaseMaterial();
00321                 }
00322         }
00323 }
00324 
00325 /* frees the bucket, only used when freeing scenes */
00326 void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat)
00327 {
00328         BucketList::iterator bit, bitp;
00329         list<RAS_MeshSlot>::iterator mit;
00330         int i;
00331 
00332 
00333         for(i=0; i<m_SolidBuckets.size(); i++) {
00334                 RAS_MaterialBucket *bucket = m_SolidBuckets[i];
00335                 if (mat == bucket->GetPolyMaterial()) {
00336                         m_SolidBuckets.erase(m_SolidBuckets.begin()+i);
00337                         delete bucket;
00338                         i--;
00339                 }
00340         }
00341 
00342         for(int i=0; i<m_AlphaBuckets.size(); i++) {
00343                 RAS_MaterialBucket *bucket = m_AlphaBuckets[i];
00344                 if (mat == bucket->GetPolyMaterial()) {
00345                         m_AlphaBuckets.erase(m_AlphaBuckets.begin()+i);
00346                         delete bucket;
00347                         i--;
00348                 }
00349         }
00350 }
00351 
00352 //#include <stdio.h>
00353 
00354 void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene)
00355 {
00356         /* concatinate lists */
00357         // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
00358         BucketList::iterator it;
00359 
00360         for (it = other->GetSolidBuckets().begin(); it != other->GetSolidBuckets().end(); ++it)
00361                 (*it)->GetPolyMaterial()->Replace_IScene(scene);
00362 
00363         GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() );
00364         other->GetSolidBuckets().clear();
00365 
00366         for (it = other->GetAlphaBuckets().begin(); it != other->GetAlphaBuckets().end(); ++it)
00367                 (*it)->GetPolyMaterial()->Replace_IScene(scene);
00368 
00369         GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() );
00370         other->GetAlphaBuckets().clear();
00371         //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
00372 }
00373