//----------------------------------------------------------------------- OpcodeCollisionBoundingBoxShape::~OpcodeCollisionBoundingBoxShape() { // ½â¾öÄÚ´æй© OGRE_DELETE(mMeshInterface); OGRE_DELETE(mCollisionModel); if(mAutoDeleteIndexList) { OGRE_DELETE_ARRAY(mIndexList); } if(mAutoDeleteVertexList) { OGRE_DELETE_ARRAY(mVertexList); } }
//----------------------------------------------------------------------- bool ConvexBody::operator == ( const ConvexBody& rhs ) const { if ( getPolygonCount() != rhs.getPolygonCount() ) return false; // Compare the polygons. They may not be in correct order. // A correct convex body does not have identical polygons in its body. bool *bChecked = new bool[ getPolygonCount() ]; for ( size_t i=0; i<getPolygonCount(); ++i ) { bChecked[ i ] = false; } for ( size_t i=0; i<getPolygonCount(); ++i ) { bool bFound = false; for ( size_t j=0; j<getPolygonCount(); ++j ) { const Polygon& pA = getPolygon( i ); const Polygon& pB = rhs.getPolygon( j ); if ( pA == pB ) { bFound = true; bChecked[ i ] = true; break; } } if ( bFound == false ) { OGRE_DELETE_ARRAY( bChecked ); return false; } } for ( size_t i=0; i<getPolygonCount(); ++i ) { if ( bChecked[ i ] != true ) { OGRE_DELETE_ARRAY( bChecked ); return false; } } OGRE_DELETE_ARRAY( bChecked ); return true; }
GridDecal::~GridDecal() { OGRE_DELETE_ARRAY(m_gridPositions); if(m_decal) { m_sceneMgr->destroyManualObject(m_decal); m_decal = 0; } }
// 当属性改变了,需要重构贴花的时候 void GridDecal::updateDecal() { #define WIDTH_POS_COUNT (m_widthGridCount + 1) #define HEIGHT_POS_COUNT (m_heightGridCount + 1) // 显示整个节点 m_node->setVisible(m_visible); // 不可视就不更新了 if(!m_visible) { return; } // 错误数据检查 if(m_heightGridCount == 0 || m_widthGridCount == 0) return; // 如果网格大小改变了,就重构 if((m_dirty & (GRID_DECAL_DIRTY_WIDTH_GRID_COUNT | GRID_DECAL_DIRTY_HEIGHT_GRID_COUNT)) || m_gridPositions == 0 ) { OGRE_DELETE_ARRAY(m_gridPositions); m_gridPositions = new Vector3[WIDTH_POS_COUNT * HEIGHT_POS_COUNT]; memset(m_gridPositions , 0 , sizeof(Vector3) * WIDTH_POS_COUNT * HEIGHT_POS_COUNT); } // 位置、深度、大小会导致平面重新定义 if(m_dirty & (DIRTY_POSITION | DIRTY_DEPTH | DIRTY_SIZE | GRID_DECAL_DIRTY_WIDTH_GRID_COUNT | GRID_DECAL_DIRTY_HEIGHT_GRID_COUNT) ) { for(uint y = 0 ; y < WIDTH_POS_COUNT ; y ++) { for(uint x = 0 ; x < HEIGHT_POS_COUNT ; x ++) { // 找到与地形相交的点 if(!IDecalSystem::getSingleton().worldRayQuery(m_gridPositions[y * WIDTH_POS_COUNT + x] , m_position + Vector3(m_size.x * ((float)x / (float)WIDTH_POS_COUNT) - m_size.x / 2.0f , m_depth , m_size.y * ((float)y / (float)HEIGHT_POS_COUNT) - m_size.y / 2.0f) , m_position + Vector3(m_size.x * ((float)x / (float)WIDTH_POS_COUNT) - m_size.x / 2.0f , -m_depth , m_size.y * ((float)y / (float)HEIGHT_POS_COUNT) - m_size.y / 2.0f) ) ) { return; } // 移动到相对位置 m_gridPositions[y * WIDTH_POS_COUNT + x] -= m_position; } } // 从三点定义贴花平面 m_decalPlane.redefine(m_gridPositions[WIDTH_POS_COUNT / 2] , m_gridPositions[WIDTH_POS_COUNT * (HEIGHT_POS_COUNT - 1)] , m_gridPositions[WIDTH_POS_COUNT * HEIGHT_POS_COUNT - 1] ); } // 改变节点位置 if(m_dirty & DIRTY_POSITION) { m_node->setPosition(m_position); } // 材质名和大小会影响贴花对象的重构 if(m_dirty & (DIRTY_POSITION | DIRTY_DEPTH | DIRTY_MATERIAL_NAME | DIRTY_SIZE | GRID_DECAL_DIRTY_WIDTH_GRID_COUNT | GRID_DECAL_DIRTY_HEIGHT_GRID_COUNT) ) { // 材质贴花 if(!m_materialName.empty()) { // 创建贴花对象 if(m_decal == 0) { m_decal = m_sceneMgr->createManualObject(m_name + "_GridDecal"); m_decal->setDynamic(true); m_decal->begin(m_materialName); m_decal->position(Vector3::ZERO); m_decal->textureCoord(0,0); m_decal->index(0); m_decal->end(); // 贴花在地形之后,物件之前 m_decal->setRenderQueueGroup(RENDER_QUEUE_DECAL); attachObject(m_decal); } // 设置材质 if(m_dirty & DIRTY_MATERIAL_NAME) { m_decal->getSection(0)->setMaterialName(m_materialName); } // 更新顶点 if(m_dirty & (DIRTY_POSITION | DIRTY_DEPTH | DIRTY_SIZE | GRID_DECAL_DIRTY_WIDTH_GRID_COUNT | GRID_DECAL_DIRTY_HEIGHT_GRID_COUNT) ) { m_decal->beginUpdate(0); // 生成所有顶点 for(uint y = 0 ; y < HEIGHT_POS_COUNT ; y ++) { for(uint x = 0 ; x < WIDTH_POS_COUNT ; x ++) { m_decal->position(m_gridPositions[y * WIDTH_POS_COUNT + x]); m_decal->textureCoord((float)x / (float)WIDTH_POS_COUNT , (float)y / (float)HEIGHT_POS_COUNT); } } // 根据顶点生成索引缓冲区 for(uint y = 0 ; y < m_heightGridCount ; y ++) { for(uint x = 0 ; x < m_widthGridCount ; x ++) { uint tl = y * WIDTH_POS_COUNT + x; uint tr = y * WIDTH_POS_COUNT + x + 1; uint bl = (y + 1) * WIDTH_POS_COUNT + x; uint br = (y + 1) * WIDTH_POS_COUNT + x + 1; m_decal->quad(tl , bl , br , tr ); } } m_decal->end(); } } else { if(m_decal) { m_sceneMgr->destroyManualObject(m_decal); m_decal = 0; } } } // 改变附加对象的节点旋转 if(m_nodeAttachObject) { // 位置信息改变才需要重新设置 if(m_dirty & (DIRTY_POSITION | DIRTY_DEPTH | DIRTY_SIZE | DIRTY_OFFSET) ) { m_nodeAttachObject->setPosition(m_offsetPosition); } } }
//----------------------------------------------------------------------- void ConvexBody::clip( const Plane& pl, bool keepNegative ) { if ( getPolygonCount() == 0 ) return; // current will be used as the reference body ConvexBody current; current.moveDataFromBody(*this); OgreAssert( this->getPolygonCount() == 0, "Body not empty!" ); OgreAssert( current.getPolygonCount() != 0, "Body empty!" ); // holds all intersection edges for the different polygons Polygon::EdgeMap intersectionEdges; // clip all polygons by the intersection plane // add only valid or intersected polygons to *this for ( size_t iPoly = 0; iPoly < current.getPolygonCount(); ++iPoly ) { // fetch vertex count and ignore polygons with less than three vertices // the polygon is not valid and won't be added const size_t vertexCount = current.getVertexCount( iPoly ); if ( vertexCount < 3 ) continue; // current polygon const Polygon& p = current.getPolygon( iPoly ); // the polygon to assemble Polygon *pNew = allocatePolygon(); // the intersection polygon (indeed it's an edge or it's empty) Polygon *pIntersect = allocatePolygon(); // check if polygons lie inside or outside (or on the plane) // for each vertex check where it is situated in regard to the plane // three possibilities appear: Plane::Side clipSide = keepNegative ? Plane::POSITIVE_SIDE : Plane::NEGATIVE_SIDE; // - side is clipSide: vertex will be clipped // - side is !clipSide: vertex will be untouched // - side is NOSIDE: vertex will be untouched Plane::Side *side = new Plane::Side[ vertexCount ]; for ( size_t iVertex = 0; iVertex < vertexCount; ++iVertex ) { side[ iVertex ] = pl.getSide( p.getVertex( iVertex ) ); } // now we check the side combinations for the current and the next vertex // four different combinations exist: // - both points inside (or on the plane): keep the second (add it to the body) // - both points outside: discard both (don't add them to the body) // - first vertex is inside, second is outside: add the intersection point // - first vertex is outside, second is inside: add the intersection point, then the second for ( size_t iVertex = 0; iVertex < vertexCount; ++iVertex ) { // determine the next vertex size_t iNextVertex = ( iVertex + 1 ) % vertexCount; const Vector3& vCurrent = p.getVertex( iVertex ); const Vector3& vNext = p.getVertex( iNextVertex ); // case 1: both points inside (store next) if ( side[ iVertex ] != clipSide && // NEGATIVE or NONE side[ iNextVertex ] != clipSide ) // NEGATIVE or NONE { // keep the second pNew->insertVertex( vNext ); } // case 3: inside -> outside (store intersection) else if ( side[ iVertex ] != clipSide && side[ iNextVertex ] == clipSide ) { // Do an intersection with the plane. We use a ray with a start point and a direction. // The ray is forced to hit the plane with any option available (eigher current or next // is the starting point) // intersect from the outside vertex towards the inside one Vector3 vDirection = vCurrent - vNext; vDirection.normalise(); Ray ray( vNext, vDirection ); std::pair< bool, Real > intersect = ray.intersects( pl ); // store intersection if ( intersect.first ) { // convert distance to vector Vector3 vIntersect = ray.getPoint( intersect.second ); // store intersection pNew->insertVertex( vIntersect ); pIntersect->insertVertex( vIntersect ); } } // case 4: outside -> inside (store intersection, store next) else if ( side[ iVertex ] == clipSide && side[ iNextVertex ] != clipSide ) { // Do an intersection with the plane. We use a ray with a start point and a direction. // The ray is forced to hit the plane with any option available (eigher current or next // is the starting point) // intersect from the outside vertex towards the inside one Vector3 vDirection = vNext - vCurrent; vDirection.normalise(); Ray ray( vCurrent, vDirection ); std::pair< bool, Real > intersect = ray.intersects( pl ); // store intersection if ( intersect.first ) { // convert distance to vector Vector3 vIntersect = ray.getPoint( intersect.second ); // store intersection pNew->insertVertex( vIntersect ); pIntersect->insertVertex( vIntersect ); } pNew->insertVertex( vNext ); } // else: // case 2: both outside (do nothing) } // insert the polygon only, if at least three vertices are present if ( pNew->getVertexCount() >= 3 ) { // in case there are double vertices, remove them pNew->removeDuplicates(); // in case there are still at least three vertices, insert the polygon if ( pNew->getVertexCount() >= 3 ) { this->insertPolygon( pNew ); } else { // delete pNew because it's empty or invalid freePolygon(pNew); pNew = 0; } } else { // delete pNew because it's empty or invalid freePolygon(pNew); pNew = 0; } // insert intersection polygon only, if there are two vertices present if ( pIntersect->getVertexCount() == 2 ) { intersectionEdges.insert( Polygon::Edge( pIntersect->getVertex( 0 ), pIntersect->getVertex( 1 ) ) ); } // delete intersection polygon // vertices were copied (if there were any) freePolygon(pIntersect); pIntersect = 0; // delete side info OGRE_DELETE_ARRAY( side ); } // if the polygon was partially clipped, close it // at least three edges are needed for a polygon if ( intersectionEdges.size() >= 3 ) { Polygon *pClosing = allocatePolygon(); // Analyze the intersection list and insert the intersection points in ccw order // Each point is twice in the list because of the fact that we have a convex body // with convex polygons. All we have to do is order the edges (an even-odd pair) // in a ccw order. The plane normal shows us the direction. Polygon::EdgeMap::iterator it = intersectionEdges.begin(); // check the cross product of the first two edges Vector3 vFirst = it->first; Vector3 vSecond = it->second; // remove inserted edge intersectionEdges.erase( it ); Vector3 vNext; // find mating edge if (findAndEraseEdgePair(vSecond, intersectionEdges, vNext)) { // detect the orientation // the polygon must have the same normal direction as the plane and then n Vector3 vCross = ( vFirst - vSecond ).crossProduct( vNext - vSecond ); bool frontside = ( pl.normal ).directionEquals( vCross, Degree( 1 ) ); // first inserted vertex Vector3 firstVertex; // currently inserted vertex Vector3 currentVertex; // direction equals -> front side (walk ccw) if ( frontside ) { // start with next as first vertex, then second, then first and continue with first to walk ccw pClosing->insertVertex( vNext ); pClosing->insertVertex( vSecond ); pClosing->insertVertex( vFirst ); firstVertex = vNext; currentVertex = vFirst; #ifdef _DEBUG_INTERSECTION_LIST std::cout << "Plane: n=" << pl.normal << ", d=" << pl.d << std::endl; std::cout << "First inserted vertex: " << *next << std::endl; std::cout << "Second inserted vertex: " << *vSecond << std::endl; std::cout << "Third inserted vertex: " << *vFirst << std::endl; #endif } // direction does not equal -> back side (walk cw) else { // start with first as first vertex, then second, then next and continue with next to walk ccw pClosing->insertVertex( vFirst ); pClosing->insertVertex( vSecond ); pClosing->insertVertex( vNext ); firstVertex = vFirst; currentVertex = vNext; #ifdef _DEBUG_INTERSECTION_LIST std::cout << "Plane: n=" << pl.normal << ", d=" << pl.d << std::endl; std::cout << "First inserted vertex: " << *vFirst << std::endl; std::cout << "Second inserted vertex: " << *vSecond << std::endl; std::cout << "Third inserted vertex: " << *next << std::endl; #endif } // search mating edges that have a point in common // continue this operation as long as edges are present while ( !intersectionEdges.empty() ) { if (findAndEraseEdgePair(currentVertex, intersectionEdges, vNext)) { // insert only if it's not the last (which equals the first) vertex if ( !intersectionEdges.empty() ) { currentVertex = vNext; pClosing->insertVertex( vNext ); } } else { // degenerated... break; } } // while intersectionEdges not empty // insert polygon (may be degenerated!) this->insertPolygon( pClosing ); } // mating intersection edge NOT found! else { freePolygon(pClosing); } } // if intersectionEdges contains more than three elements }