|
Blender
V2.59
|
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