Blender V2.61 - r43446

RAS_BucketManager.cpp

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