Blender V2.61 - r43446
|
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