#include "RenderQueue.h" #include "SceneEntity.h" #include "Geometry.h" #include "Texture.h" #include "Material.h" #include "Camera.h" #include "Shape.h" using namespace std; namespace CHCDemoEngine { inline static bool CompDist(RenderQueueBucket *b1, RenderQueueBucket *b2) { return (b1->mMinDistance < b2->mMinDistance); } RenderQueue::RenderQueue(): mState(NULL), mMinSizeForSorting(3), mCamera(NULL), mNumEntries(0) { } RenderQueue::RenderQueue(RenderState *state, Camera *cam): mState(state), mMinSizeForSorting(3), mCamera(cam), mNumEntries(0) { } RenderQueue::~RenderQueue() { for (size_t i = 0; i < mBuckets.size(); ++ i) { DEL_PTR(mBuckets[i]); } } bool RenderQueue::FitsInBucket(Shape *shape, size_t idx) const { Material *mat = shape->GetMaterial(); // test if entity belongs to this bucket // note: rather slows down the application for some reason!! if (mat->IsAlphaTestEnabled() != mBuckets[idx]->mAlphaTestEnabled) return false; if (mat->IsCullFaceEnabled() != mBuckets[idx]->mCullFaceEnabled) return false; const bool hasTexture = (mat->GetTexture() != NULL); if (hasTexture != mBuckets[idx]->mHasTexture) return false; if (hasTexture) { if (mat->GetTexture()->GetWidth() != mBuckets[idx]->mTexWidth) return false; if (mat->GetTexture()->GetHeight() != mBuckets[idx]->mTexHeight) return false; } return true; } void RenderQueue::Enqueue(SceneEntity *entity) { ShapeContainer::iterator sit, sit_end; entity->GetCurrentLODLevel(sit, sit_end); for (; sit != sit_end; ++ sit) { Enqueue(*sit); } } void RenderQueue::Enqueue(Shape *shape) { RenderQueueBucket *bucket; ++ mNumEntries; if (shape->mRenderQueueBucket) { bucket = shape->mRenderQueueBucket; } else { bool bucketFound = false; size_t i = 0; for (; i < mBuckets.size(); ++ i) { if (bucketFound = FitsInBucket(shape, i)) break; } // create new bucket if (!bucketFound) { RenderQueueBucket *bucket = new RenderQueueBucket(); bucket->mMinDistance = -1; Material *mat = shape->GetMaterial(); bucket->mAlphaTestEnabled = mat->IsAlphaTestEnabled(); bucket->mCullFaceEnabled = mat->IsCullFaceEnabled(); const bool hasTexture = (mat->GetTexture() != NULL); bucket->mHasTexture = hasTexture; bucket->mTexWidth = hasTexture ? mat->GetTexture()->GetWidth() : 0; bucket->mTexHeight = hasTexture ? mat->GetTexture()->GetHeight() : 0; mBuckets.push_back(bucket); //cout << "num buckets: " << (int)mBuckets.size() << endl; } bucket = mBuckets[i]; shape->mRenderQueueBucket = bucket; } if (bucket->mMinDistance < .0f) { // assume that the incoming nodes are ordered by distance // => set min dist on first incoming node const Vector3 v = shape->GetCenter() - mCamera->GetPosition(); const float dist = SqrMagnitude(v); bucket->mMinDistance = dist; } bucket->mShapes.push_back(shape); } void RenderQueue::Clear() { for (size_t i = 0; i < mBuckets.size(); ++ i) { mBuckets[i]->mMinDistance = -1; mBuckets[i]->mShapes.clear(); } mNumEntries = 0; } void RenderQueue::SetRenderState(RenderState *state) { mState = state; } void RenderQueue::Render() { // sort the buckets Sort(); // render all buckets for (size_t i = 0; i < mBuckets.size(); ++ i) { ShapeContainer::const_iterator sit, sit_end = mBuckets[i]->mShapes.end(); for (sit = mBuckets[i]->mShapes.begin(); sit != sit_end; ++ sit) { Shape *shape = *sit; shape->Render(mState); } } //Print(); } void RenderQueue::Print() { for (size_t i = 0; i < mBuckets.size(); ++ i) { Debug << "\n******\nbucket " << (int)i << endl; ShapeContainer::const_iterator sit, sit_end = mBuckets[i]->mShapes.end(); for (sit = mBuckets[i]->mShapes.begin(); sit != sit_end; ++ sit) { Shape *shape = *sit; Material *mat = shape->GetMaterial(); int tsize = mat->GetTexture() ? mat->GetTexture()->GetByteSize() : 0; float dist = SqrMagnitude(shape->GetBoundingBox().Center() - mCamera->GetPosition()); Debug << "e: " << shape << " a: " << mat->IsAlphaTestEnabled() << " s: " << tsize << " d: " << dist << " " << endl; } } } void RenderQueue::Sort() { // sort buckets itself sort(mBuckets.begin(), mBuckets.end(), CompDist); } void RenderQueue::Apply() { Render(); Clear(); } }