#include "stdafx.h" #ifndef CODE_INGAME #include #include "Terrain.h" #include "EditableBaseObj.h" #include "Utility.h" // 地形最大高度 暂用 #define MAX_TERRAIN_HEIGHT 100 NiBoxBV stQuadNode::GetChildAABB(int iWhich) { float fx = boundingBox.GetExtent( 0 ); fx *= 0.5f; float fy = boundingBox.GetExtent( 1 ); fy *= 0.5f; // 计算BoundingBox中心 // 注意:Gamebryo 使用右手坐标系,Z轴正方向指向屏幕上方向,Y指向屏幕内 NiPoint3 vCenter = boundingBox.GetCenter(); if ( iWhich == 0 ) { vCenter.x -= fx; vCenter.y += fy; } else if ( iWhich == 1 ) { vCenter.x += fx; vCenter.y += fy; } else if ( iWhich == 2) { vCenter.x -= fx; vCenter.y -= fy; } else if ( iWhich == 3 ) { vCenter.x += fx; vCenter.y -= fy; } NiBoxBV aabb; aabb.SetCenter( vCenter ); aabb.SetExtent( 0, fx ); aabb.SetExtent( 1, fy ); aabb.SetExtent( 2, boundingBox.GetExtent(2) ); return aabb; } stQuadNode* stQuadNode::GetChild(int iWhich) { // 参数合法性检查 assert(iWhich>=0 && iWhichiLevel = iLevel+1; pChild[iWhich]->iLength = iLength/2; pChild[iWhich]->pParent = this; pChild[iWhich]->boundingBox = GetChildAABB(iWhich); return pChild[iWhich]; } } NiBound GetWorldBoundFromActorNode(NiAVObject* pObj) { if (NiIsKindOf(NiNode, pObj)) { NiTransform trans = pObj->GetLocalTransform(); pObj->SetTranslate(NiPoint3::ZERO); pObj->SetRotate(NiMatrix3::IDENTITY); pObj->SetScale(1.0f); pObj->Update(0.0f); pObj->UpdateNodeBound(); pObj->UpdateWorldBound(); pObj->UpdateSelected(0.0f); NiBound kBound = pObj->GetWorldBound(); pObj->SetLocalTransform(trans); //pObj->SetScale(trans.m_fScale); //pObj->SetTranslate(trans.m_Translate); //pObj->SetRotate(trans.m_Rotate); pObj->Update(0.0f); pObj->UpdateWorldBound(); NiPoint3 kCenter = kBound.GetCenter(); float fRadius = kBound.GetRadius(); kBound.SetCenterAndRadius(kCenter+trans.m_Translate, fRadius*trans.m_fScale); return kBound; } else { return pObj->GetWorldBound(); } } stQuadNode* stQuadNode::AttachObject(NiAVObject* pObj, int iID) { //const NiPoint3& kCenter = pObj->GetWorldBound().GetCenter(); // 取得对象的中心点 if (!BSIntersectAABB_2D(pObj->GetWorldBound(), boundingBox))//GetWorldBoundFromActorNode(pObj) { return NULL; } // 如果结点半径大于子节点,或者节点不可再分,将对象加入当前结点 if (pObj->GetWorldBound().GetRadius() >= iLength/2 || boundingBox.GetExtent(0) <= MIN_EDGE_LENGTH) { niObjsArray.push_back(pObj); iEntityIDArray.push_back(iID); return this; } // 分别测试4个子节点的包围盒。 // 如果被添加对象在某节点内,将对象交给该子节点处理 for (int i=0; iGetWorldBound(), aabb) == 2) { return GetChild(i)->AttachObject(pObj, iID); } else { continue; } } // 没有子节点完全包含该对象。将对象添加到本节点 niObjsArray.push_back(pObj); iEntityIDArray.push_back(iID); return this; } NiNodePtr stQuadNode::BuildSceneGraph() { NiNodePtr pkNiNode = NiNew NiNode(4); // 加入子节点构造的场景图 for (int i=0; iBuildSceneGraph(); pkNiNode->AttachChild(pSubScene, false); } } // 将本节点连接的对象加入场景图 vector< NiAVObject* >::iterator itor = niObjsArray.begin(); while (itor != niObjsArray.end()) { pkNiNode->AttachChild(*itor, true); itor++; } return pkNiNode; } TiXmlElement* stQuadNode::GetAsXMLElement() { TiXmlElement* elmtThisNode = new TiXmlElement("Node"); // 添加所有 entity id for (unsigned int i=0; iSetAttribute("EntityID", iEntityIDArray[i]); elmtThisNode->LinkEndChild(elmtEntity); } // 添加所有子节点 for (int i=0; iLinkEndChild(pChild[i]->GetAsXMLElement()); } } return elmtThisNode; } /// QuadTree 构造 CQuadTree::CQuadTree( const NiPoint3& kCenter, const NiPoint3& kExtends) :m_pRoot(NULL) { //assert(pTerrain); //NiPoint2 terrSize = pTerrain->GetTotalSize(); m_pRoot = new stQuadNode(); m_pRoot->boundingBox.SetCenter(kCenter); m_pRoot->boundingBox.SetExtent(0, kExtends.x); m_pRoot->boundingBox.SetExtent(1, kExtends.y); m_pRoot->boundingBox.SetExtent(2, kExtends.z); m_pRoot->iLevel = 0; m_pRoot->iLength = max(kExtends.x, kExtends.y) * 2; m_pRoot->pParent = NULL; } void CQuadTree::_Destroy() { _DestroyNode( m_pRoot ); } NiNodePtr CQuadTree::BuildSceneGraph() { return m_pRoot->BuildSceneGraph(); } void CQuadTree::_DestroyNode( stQuadNode*& pNode ) { for ( int i = 0; i < QUAD_NUM; ++i ) { if ( NULL != pNode->pChild[i] ) _DestroyNode( pNode->pChild[i] ); } SAFE_DELETE( pNode ); } TiXmlElement* CQuadTree::GetAsXMLElement() { TiXmlElement* elmtRoot = new TiXmlElement("ChunkEntity"); if (m_pRoot != NULL) { elmtRoot->LinkEndChild(m_pRoot->GetAsXMLElement()); } return elmtRoot; } stQuadNode* CQuadTree::AttachObject(NiAVObject* pObj, int iID) { return m_pRoot->AttachObject(pObj, iID); } #endif // 文件结尾 // 创建可视列表 函数作废 //void CQuadTree::BuilderVisibleSet(NiCamera * pCamera, NiVisibleArray *pVisible) //{ // // 参数合法性检查 // assert(pCamera && pVisible && m_pRoot); // // NiFrustumPlanes frustumPlanes(*pCamera); // m_pRoot->BuilderVisibleSet(&frustumPlanes, pVisible); // //} // 函数作废,请不要删除。也许以后有参考价值 //void stQuadNode::BuilderVisibleSet(NiFrustumPlanes* pFrustum, NiVisibleArray *pVisible) //{ // // Determine if the object is not visible by comparing its world // // bound to each culling plane. // unsigned int uiSaveActive = pFrustum->GetActivePlaneState(); // unsigned int i; // // for (i = 0; i < NiFrustumPlanes::MAX_PLANES; i++) // { // if (pFrustum->IsPlaneActive(i)) // { // int iSide = AABBIntersectPlane(boundingBox, pFrustum->GetPlane(i)); // // if (iSide == NiPlane::NEGATIVE_SIDE) // { // // The object is not visible since it is on the negative // // side of the plane. // break; // } // else if (iSide == NiPlane::POSITIVE_SIDE) // { // // The object is fully on the positive side of the plane, // // so there is no need to compare child objects to this // // plane. // pFrustum->DisablePlane(i); // } // else //if (iSide == NiPlane::NO_SIDE) // { // } // } // } // // if (i == NiFrustumPlanes::MAX_PLANES) // 对于所有平面,没有在平面负方向的 // { // // 将本节点所有对象加入可视列表中 // vector< CEditableBaseObj* >::iterator itor = objsArray.begin(); // while (itor != objsArray.end()) // { // NiNode* pkNiNode= (*itor)->GetNode(); // NiGeometry* pkGeo = NiDynamicCast(NiGeometry, pkNiNode); // if (pkGeo != NULL) // { // pVisible->Add(*pkGeo); // } // // itor++; // } // // 遍历所有存在子节点 // for (int k=0; kBuilderVisibleSet(pFrustum, pVisible); // } // } // } // else // { // //该节点在 frustum 中不可见 // } // // pFrustum->SetActivePlaneState(uiSaveActive); //}