void QuadNode::generateLists() { if(items.size() > 0) { if(!listid) listid = glGenLists(1); glNewList(listid, GL_COMPILE); for(std::list<QuadItem*>::iterator it = items.begin(); it != items.end(); it++) { QuadItem* oi = (*it); oi->drawQuadItem(); } glEndList(); return; } if(children.size() > 0) { for(int i=0;i<4;i++) { QuadNode* c = children[i]; if(!c->empty()) { c->generateLists(); } } } }
void QuadNode::outline() { bounds.draw(); if(children.size()==0) return; for(int i=0;i<4;i++) { QuadNode* c = children[i]; if(c!=0) { c->outline(); } } }
void QuadNode::release() { for (int i = eQuadNode_LeftBottom; i != eQuadNode_Size; ++i) { QuadNode* c = children_[i]; if (c) { c->release(); } } releaseImp_(); }
bool isChildOf(const QuadNode& node) const { if (level() < node.level()) { for (size_t i = totalLevels - 1; i >= node.level(); --i) { if (nodeCode.x[i] != node.locationCode().x[i] || nodeCode.y[i] != node.locationCode().y[i]) { return false; } } return true; } return false; }
void QuadNode::outlineItems() { if(items.empty() && children.empty()) return; for(std::list<QuadItem*>::iterator it = items.begin(); it != items.end(); it++) { QuadItem* oi = (*it); oi->quadItemBounds.draw(); } if(children.empty()) return; for(int i=0;i<4;i++) { QuadNode* c = children[i]; if(c!=0) { c->outlineItems(); } } }
void QuadNode::outline() { //bounds.draw(); if(!items.empty()) { bounds.draw(); /*glBegin(GL_LINES); glVertex2fv(bounds.min); glVertex2fv(bounds.max); glEnd();*/ } if(children.empty()) return; for(int i=0;i<4;i++) { QuadNode* c = children[i]; if(c!=0) { c->outline(); } } }
int QuadNode::draw(Frustum& frustum) { if(listid && items.size()) { glPushMatrix(); glCallList(listid); glPopMatrix(); return 1; } int drawn = 0; if(children.size() > 0) { for(int i=0;i<4;i++) { QuadNode* c = children[i]; if(!c->empty() && frustum.boundsInFrustum(c->bounds)) { drawn += c->draw(frustum); } } } return drawn; }
QuadNode<T, lev>& nextNode(QuadNode<T, lev>& node) { if (node.hasChildren()) { if (node.childExists(0, 0)) return node.child(0, 0); else if (node.childExists(0, 1)) return node.child(0, 1); else if (node.childExists(1, 0)) return node.child(1, 0); else return node.child(1, 1); } else { QuadNode<T, lev>* refNode = &node; // initial prepare for the first check of parent node bool x = refNode->locationCode().x[refNode->level()]; bool y = refNode->locationCode().y[refNode->level()]; while (*refNode != refNode->parent()) { refNode = &(refNode->parent()); // evaluate node number in node->parent() child list and check only children with // higher index. for (uint32_t i = QuadNode<T, lev>::locToInt(x, y) + 1; i < 4; ++i) { bool cx = (i & 2) >> 1; bool cy = i & 1; if (refNode->childExists(cx, cy)) { return refNode->child(cx, cy); } } // prepare the next (parent) node to check x = refNode->locationCode().x[refNode->level()]; y = refNode->locationCode().y[refNode->level()]; } // At this point refNode == refNode.parent(), so it's a header. We'll return it as // nextNode() of the last (rightmost) node in a tree. return *refNode; } }
QuadNode<T, lev>& previousNode(QuadNode<T, lev>& node) { // If header node is given, then its previousNode is the rightmost one. // requirement: --end() if (node.parent() == node) return node.rightMostNode(); QuadNode<T, lev>* refNode = &node; bool x = refNode->locationCode().x[refNode->level()]; bool y = refNode->locationCode().y[refNode->level()]; refNode = &(refNode->parent()); for (int i = QuadNode<T, lev>::locToInt(x, y) - 1; i >= 0; --i) { bool cx = (i & 2) >> 1; bool cy = i & 1; if (refNode->childExists(cx, cy)) { refNode = &(refNode->child(cx, cy)); while (refNode->hasChildren()) { if (refNode->childExists(1, 1)) refNode = &(refNode->child(1, 1)); else if (refNode->childExists(1, 0)) refNode = &(refNode->child(1, 0)); else if (refNode->childExists(0, 1)) refNode = &(refNode->child(0, 1)); else refNode = &(refNode->child(0, 0)); } return *refNode; } } // If no previous sibling has been found, this will actually return node.parent() // The special case is root: its previousNode is header node and previousNode(header) is // rightmost node. It's some kind of circular buffer and we'll let iterators handle this case to // avoid it (e.g by setting (--begin())::node to nullptr) return *refNode; }
void PatchMap::initialize( PatchTable const & patchTable ) { int nfaces = 0, narrays = (int)patchTable.GetNumPatchArrays(), npatches = (int)patchTable.GetNumPatchesTotal(); if (! narrays || ! npatches) return; // populate subpatch handles vector _handles.resize(npatches); for (int parray=0, current=0; parray<narrays; ++parray) { ConstPatchParamArray params = patchTable.GetPatchParams(parray); int ringsize = patchTable.GetPatchArrayDescriptor(parray).GetNumControlVertices(); for (Index j=0; j < patchTable.GetNumPatches(parray); ++j) { Handle & h = _handles[current]; h.arrayIndex = parray; h.patchIndex = current; h.vertIndex = j * ringsize; nfaces = std::max(nfaces, (int)params[j].GetFaceId()); ++current; } } ++nfaces; // temporary vector to hold the quadtree while under construction std::vector<QuadNode> quadtree; // reserve memory for the octree nodes (size is a worse-case approximation) quadtree.reserve( nfaces + npatches ); // each coarse face has a root node associated to it that we need to initialize quadtree.resize(nfaces); // populate the quadtree from the FarPatchArrays sub-patches for (Index parray=0, handleIndex=0; parray<narrays; ++parray) { ConstPatchParamArray params = patchTable.GetPatchParams(parray); for (int i=0; i < patchTable.GetNumPatches(parray); ++i, ++handleIndex) { PatchParam const & param = params[i]; unsigned short depth = param.GetDepth(); QuadNode * node = &quadtree[ params[i].GetFaceId() ]; if (depth==(param.NonQuadRoot() ? 1 : 0)) { // special case : regular BSpline face w/ no sub-patches node->SetChild( handleIndex ); continue; } int u = param.GetU(), v = param.GetV(), pdepth = param.NonQuadRoot() ? depth-2 : depth-1, half = 1 << pdepth; for (unsigned char j=0; j<depth; ++j) { int delta = half >> 1; int quadrant = resolveQuadrant(half, u, v); assert(quadrant>=0); half = delta; if (j==pdepth) { // we have reached the depth of the sub-patch : add a leaf assert( ! node->children[quadrant].isSet ); node->SetChild(quadrant, handleIndex, true); break; } else { // travel down the child node of the corresponding quadrant if (! node->children[quadrant].isSet) { // create a new branch in the quadrant node = addChild(quadtree, node, quadrant); } else { // travel down an existing branch node = &(quadtree[ node->children[quadrant].idx ]); } } } } } // copy the resulting quadtree to eliminate un-unused vector capacity _quadtree = quadtree; }
void SceneManager::Update() { RenderLayerManager & renderManager = RenderLayerManager::GetRenderLayerManager(); const PVRTVec3 center = renderManager.GetCenter(); float occlusionRadius = renderManager.GetOcclusionRadius(); PVRTVec4 vecA( mLookMtx->f[12], 0.0f, mLookMtx->f[14], 1); PVRTVec4 vecB( GLOBAL_SCALE * FRUSTUM_W, 0.0f, GLOBAL_SCALE * FRUSTUM_D, 1); PVRTVec4 vecC( GLOBAL_SCALE * -FRUSTUM_W, 0.0f, GLOBAL_SCALE * FRUSTUM_D, 1); vecB = *mLookMtx * vecB; vecC = *mLookMtx * vecC; PVRTVec2 A(vecA.x, vecA.z); PVRTVec2 B(vecB.x, vecB.z); PVRTVec2 C(vecC.x, vecC.z); mToApplyCount = 0; if (mQuadTree) { static QuadNode * quadNodes[256]={0}; int quadNodeCount = 0; //mQuadTree->GetQuads(center.x, center.z, occlusionRadius, quadNodes, quadNodeCount); mQuadTree->GetQuadsCameraFrustum(quadNodes, quadNodeCount, mLookMtx); quadNodeCount--; bool useFrustumCulling = true; //!!!!!!!!!!!!!!!!!!!!! for (int quad = quadNodeCount ; quad >=0 ; quad--) { QuadNode * pQuadNode = quadNodes[quad]; List & dataList = pQuadNode->GetDataList(); ListIterator listIter(dataList); while( Node * pRootNode = (Node*)listIter.GetPtr() ) { if (!pRootNode->IsVisible()) continue; //pRootNode->UpdateWithoutChildren(); bool useOcclusionRadius = pRootNode->GetUseOcclusionCulling(); PVRTVec3 worldPos = pRootNode->GetWorldTranslation(); if (!useFrustumCulling && useOcclusionRadius) { PVRTVec3 distVec = worldPos - center; if ( distVec.lenSqr() < MM(occlusionRadius) ) { pRootNode->SetInFrustum(true); pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; } else { pRootNode->SetInFrustum(false); } } else if (useFrustumCulling) { PVRTVec2 P(worldPos.x, worldPos.z); PVRTVec2 v0 = C - A; PVRTVec2 v1 = B - A; PVRTVec2 v2 = P - A; // Compute dot products float dot00 = v0.dot(v0); float dot01 = v0.dot(v1); float dot02 = v0.dot(v2); float dot11 = v1.dot(v1); float dot12 = v1.dot(v2); // Compute barycentric coordinates float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); float u = (dot11 * dot02 - dot01 * dot12) * invDenom; float v = (dot00 * dot12 - dot01 * dot02) * invDenom; bool addToList = false; // Check if point is in triangle //PVRTVec3 distVec = worldPos - center; //if ( distVec.lenSqr() < MM(occlusionRadius) ) { if ( (u > 0) && (v > 0) && (u + v < 1)) { addToList = true; } else if ( Collision::CircleTriangleEdgeIntersection(A,B,P, pRootNode->GetRadius() ) ) { addToList = true; } else if ( Collision::CircleTriangleEdgeIntersection(A,C,P, pRootNode->GetRadius() )) { addToList = true; } if (addToList) { pRootNode->SetInFrustum(true); //pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; } else { pRootNode->SetInFrustum(false); } } //else //{ // pRootNode->SetInFrustum(false); //} } else { pRootNode->SetInFrustum(true); //pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; } } } } for (int n=0;n<mNodeCount;n++) { Node * pRootNode = mRootNodes[n]; if (!pRootNode->IsVisible()) continue; pRootNode->UpdateWithoutChildren(); bool useOcclusionRadius = pRootNode->GetUseOcclusionCulling(); PVRTVec3 worldPos = pRootNode->GetWorldTranslation(); PVRTVec3 distVec = worldPos - center; if (useOcclusionRadius) { if ( distVec.lenSqr() < MM(occlusionRadius) ) { PVRTVec2 P(worldPos.x, worldPos.z); PVRTVec2 v0 = C - A; PVRTVec2 v1 = B - A; PVRTVec2 v2 = P - A; // Compute dot products float dot00 = v0.dot(v0); float dot01 = v0.dot(v1); float dot02 = v0.dot(v2); float dot11 = v1.dot(v1); float dot12 = v1.dot(v2); // Compute barycentric coordinates float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); float u = (dot11 * dot02 - dot01 * dot12) * invDenom; float v = (dot00 * dot12 - dot01 * dot02) * invDenom; bool addToList = false; // Check if point is in triangle //PVRTVec3 distVec = worldPos - center; //if ( distVec.lenSqr() < MM(occlusionRadius) ) { if ( (u > 0) && (v > 0) && (u + v < 1)) { addToList = true; } else if ( Collision::CircleTriangleEdgeIntersection(A,B,P, pRootNode->GetRadius() ) ) { addToList = true; } else if ( Collision::CircleTriangleEdgeIntersection(A,C,P, pRootNode->GetRadius() )) { addToList = true; } if (addToList) { pRootNode->SetInFrustum(true); pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; } else { pRootNode->SetInFrustum(false); } } /* pRootNode->SetInFrustum(true); pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; */ } else { pRootNode->SetInFrustum(false); } } else { pRootNode->SetInFrustum(true); pRootNode->Update(); mToApply[mToApplyCount] = pRootNode; mToApplyCount++; } /* PVRTVec3 worldPos = pRootNode->GetWorldTranslation(); PVRTVec3 distVec = worldPos - center; if (!pRootNode->GetUseOcclusionCulling()) { pRootNode->SetInFrustum(true); } else if ( distVec.lenSqr() < occlusionRadius ) { pRootNode->SetInFrustum(true); } else { pRootNode->SetInFrustum(false); } */ } }