#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 { Technique *tech = shape->GetMaterial()->GetDefaultTechnique(); // test if entity belongs to this bucket // note: rather slows down the application for some reason!! if (tech->IsAlphaTestEnabled() != mBuckets[idx]->mAlphaTestEnabled) { cout << "a"; return false; } if (tech->IsCullFaceEnabled() != mBuckets[idx]->mCullFaceEnabled) { cout << "b"; return false; } if (tech->IsColorWriteEnabled() != mBuckets[idx]->mColorWriteEnabled) { cout << "c"; return false; } if (tech->IsLightingEnabled() != mBuckets[idx]->mLightingEnabled) { cout << "d"; return false; } if (tech->IsDepthWriteEnabled() != mBuckets[idx]->mDepthWriteEnabled) { cout << "e"; return false; } const bool hasTexture = (tech->GetTexture() != NULL); if (hasTexture != mBuckets[idx]->mHasTexture) { cout << "f"; return false; } if (hasTexture) { if (tech->GetTexture()->GetWidth() != mBuckets[idx]->mTexWidth) { cout << "g"; return false; } if (tech->GetTexture()->GetHeight() != mBuckets[idx]->mTexHeight) { cout << "h"; return false; } if (tech->GetTexture()->GetFormat() != mBuckets[idx]->mTexFormat) { cout << "i"; return false; } } if (!tech->GetFragmentProgram() && mBuckets[idx]->mHasFragmentProgram) { cout << "j"; return false; } if (!tech->GetVertexProgram() && mBuckets[idx]->mHasVertexProgram) { cout << "h"; 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; Technique *tech = shape->GetMaterial()->GetDefaultTechnique(); bucket->mAlphaTestEnabled = tech->IsAlphaTestEnabled(); bucket->mCullFaceEnabled = tech->IsCullFaceEnabled(); bucket->mColorWriteEnabled = tech->IsColorWriteEnabled(); bucket->mLightingEnabled = tech->IsLightingEnabled(); bucket->mDepthWriteEnabled = tech->IsDepthWriteEnabled(); Texture *tex = tech->GetTexture(); if (tex != NULL) { bucket->mHasTexture = true; bucket->mTexWidth = tex->GetWidth(); bucket->mTexHeight = tex->GetHeight(); bucket->mTexFormat = tex->GetFormat(); } else { bucket->mHasTexture = false; bucket->mTexWidth = 0; bucket->mTexHeight = 0; bucket->mTexFormat = 0; } bucket->mHasVertexProgram = tech->GetVertexProgram() != NULL; bucket->mHasFragmentProgram = tech->GetFragmentProgram() != NULL; 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; Technique *tech = shape->GetMaterial()->GetDefaultTechnique(); int tsize = tech->GetTexture() ? tech->GetTexture()->GetByteSize() : 0; float dist = SqrMagnitude(shape->GetBoundingBox().Center() - mCamera->GetPosition()); Debug << "e: " << shape << " a: " << tech->IsAlphaTestEnabled() << " s: " << tsize << " d: " << dist << " " << endl; } } } void RenderQueue::Sort() { // sort buckets itself sort(mBuckets.begin(), mBuckets.end(), CompDist); } void RenderQueue::Apply() { Render(); Clear(); } }