//////////////////////////////////////////////////////////////////////////////// // splitNode void MaBSPTree::splitNode( MaBSPNode* pNode ) { MaBSPNode* pSwappedNode = NULL; BcBSPNodeList FList_; // Front list. BcBSPNodeList BList_; // Back list. // Move non coinciding node to the front. putNonCoincidingNodeAtTheFront( pNode->WorkingList_ ); // Split up this nodes list into a front and back list. for( BcBSPNodeList::iterator It( pNode->WorkingList_.begin() ); It != pNode->WorkingList_.end(); ) { MaPlane::eClassify Classify = classifyNode( (*It), pNode->Plane_ ); // If it's coinciding use normal to determine facing. if( Classify == MaPlane::bcPC_COINCIDING ) { /* if( pNode->Plane_.normal().dot( (*It)->Plane_.normal() ) < 0.0f ) { Classify = MaPlane::bcPC_FRONT; } else { Classify = MaPlane::bcPC_FRONT; } */ // HACK, seems to work...just: Classify = MaPlane::bcPC_FRONT; } // Classify the node. switch( Classify ) { case MaPlane::bcPC_FRONT: { // Node is entirely infront. pSwappedNode = (*It); It = pNode->WorkingList_.erase( It ); FList_.push_back( pSwappedNode ); BcAssert( pSwappedNode->Vertices_.size() >= 2 ); } break; case MaPlane::bcPC_BACK: { // Node is entirely behind. pSwappedNode = (*It); It = pNode->WorkingList_.erase( It ); BList_.push_back( pSwappedNode ); BcAssert( pSwappedNode->Vertices_.size() >= 2 ); } break; case MaPlane::bcPC_SPANNING: { // Node spans the plane. Must be clipped. MaBSPNode* pFront = clipNode( (*It), MaPlane( pNode->Plane_.normal().x(), pNode->Plane_.normal().y(), pNode->Plane_.normal().z(), pNode->Plane_.d() ) ); MaBSPNode* pBack = clipNode( (*It), MaPlane( -pNode->Plane_.normal().x(), -pNode->Plane_.normal().y(), -pNode->Plane_.normal().z(), -pNode->Plane_.d() ) ); // Original node can be dropped. pSwappedNode = (*It); It = pNode->WorkingList_.erase( It ); // Add new nodes to lists. FList_.push_back( pFront ); BcAssert( pFront->Vertices_.size() >= 2 ); BList_.push_back( pBack ); BcAssert( pBack->Vertices_.size() >= 2 ); } break; default: //Bc_AssertFailMsg( "Duplicate plane in tree." ); BcBreakpoint; break; } } // Select a front and back node for each list. if( FList_.size() > 0 ) { pNode->pFront_ = (*FList_.begin()); FList_.erase( FList_.begin() ); MaBSPNode* pSwappedNode = NULL; for( BcBSPNodeList::iterator It( FList_.begin() ); It != FList_.end(); ) { pSwappedNode = (*It); It = FList_.erase( It ); pNode->pFront_->WorkingList_.push_back( pSwappedNode ); BcAssert( pSwappedNode->Vertices_.size() >= 2 ); } splitNode( pNode->pFront_ ); } if( BList_.size() > 0 ) { pNode->pBack_ = (*BList_.begin()); BList_.erase( BList_.begin() ); MaBSPNode* pSwappedNode = NULL; for( BcBSPNodeList::iterator It( BList_.begin() ); It != BList_.end(); ) { pSwappedNode = (*It); It = BList_.erase( It ); pNode->pBack_->WorkingList_.push_back( pSwappedNode ); BcAssert( pSwappedNode->Vertices_.size() >= 2 ); } splitNode( pNode->pBack_ ); } }
void ScnViewComponent::bind( RsFrame* pFrame, RsRenderSort Sort ) { RsContext* pContext = pFrame->getContext(); // Calculate the viewport. BcF32 Width = static_cast< BcF32 >( pContext->getWidth() ); BcF32 Height = static_cast< BcF32 >( pContext->getHeight() ); // If we're using a render target, we want to use it for dimensions. if( RenderTarget_.isValid() ) { Width = static_cast< BcF32 >( RenderTarget_->getWidth() ); Height = static_cast< BcF32 >( RenderTarget_->getHeight() ); } const BcF32 ViewWidth = Width_ * Width; const BcF32 ViewHeight = Height_ * Height; const BcF32 Aspect = ViewWidth / ViewHeight; // Setup the viewport. Viewport_.viewport( static_cast< BcU32 >( X_ * Width ), static_cast< BcU32 >( Y_ * Height ), static_cast< BcU32 >( ViewWidth ), static_cast< BcU32 >( ViewHeight ), Near_, Far_ ); // Create appropriate projection matrix. if( HorizontalFOV_ > 0.0f ) { ViewUniformBlock_.ProjectionTransform_.perspProjectionHorizontal( HorizontalFOV_, Aspect, Near_, Far_ ); } else { ViewUniformBlock_.ProjectionTransform_.perspProjectionVertical( VerticalFOV_, 1.0f / Aspect, Near_, Far_ ); } ViewUniformBlock_.InverseProjectionTransform_ = ViewUniformBlock_.ProjectionTransform_; ViewUniformBlock_.InverseProjectionTransform_.inverse(); // Setup view matrix. ViewUniformBlock_.InverseViewTransform_ = getParentEntity()->getWorldMatrix(); ViewUniformBlock_.ViewTransform_ = ViewUniformBlock_.InverseViewTransform_; ViewUniformBlock_.ViewTransform_.inverse(); // Clip transform. ViewUniformBlock_.ClipTransform_ = ViewUniformBlock_.ViewTransform_ * ViewUniformBlock_.ProjectionTransform_; // Upload uniforms. RsCore::pImpl()->updateBuffer( ViewUniformBuffer_, 0, sizeof( ViewUniformBlock_ ), RsResourceUpdateFlags::ASYNC, [ this ]( RsBuffer* Buffer, const RsBufferLock& Lock ) { BcMemCopy( Lock.Buffer_, &ViewUniformBlock_, sizeof( ViewUniformBlock_ ) ); } ); // Build frustum planes. // TODO: revisit this later as we don't need to do it I don't think. FrustumPlanes_[ 0 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] + ViewUniformBlock_.ClipTransform_[0][0] ), ( ViewUniformBlock_.ClipTransform_[1][3] + ViewUniformBlock_.ClipTransform_[1][0] ), ( ViewUniformBlock_.ClipTransform_[2][3] + ViewUniformBlock_.ClipTransform_[2][0] ), ( ViewUniformBlock_.ClipTransform_[3][3] + ViewUniformBlock_.ClipTransform_[3][0]) ); FrustumPlanes_[ 1 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][0] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][0] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][0] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][0] ) ); FrustumPlanes_[ 2 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] + ViewUniformBlock_.ClipTransform_[0][1] ), ( ViewUniformBlock_.ClipTransform_[1][3] + ViewUniformBlock_.ClipTransform_[1][1] ), ( ViewUniformBlock_.ClipTransform_[2][3] + ViewUniformBlock_.ClipTransform_[2][1] ), ( ViewUniformBlock_.ClipTransform_[3][3] + ViewUniformBlock_.ClipTransform_[3][1] ) ); FrustumPlanes_[ 3 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][1] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][1] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][1] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][1] ) ); FrustumPlanes_[ 4 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][2] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][2] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][2] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][2] ) ); FrustumPlanes_[ 5 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] ), ( ViewUniformBlock_.ClipTransform_[1][3] ), ( ViewUniformBlock_.ClipTransform_[2][3] ), ( ViewUniformBlock_.ClipTransform_[3][3] ) ); // Normalise frustum planes. for ( BcU32 i = 0; i < 6; ++i ) { MaVec3d Normal = FrustumPlanes_[ i ].normal(); BcF32 Scale = 1.0f / -Normal.magnitude(); FrustumPlanes_[ i ] = MaPlane( FrustumPlanes_[ i ].normal().x() * Scale, FrustumPlanes_[ i ].normal().y() * Scale, FrustumPlanes_[ i ].normal().z() * Scale, FrustumPlanes_[ i ].d() * Scale ); } // Setup render node to set the frame buffer, viewport, and clear colour. // TODO: Pass this in with the draw commands down the line. ScnViewComponentViewport* pRenderNode = pFrame->newObject< ScnViewComponentViewport >(); pRenderNode->Sort_ = Sort; pRenderNode->FrameBuffer_ = FrameBuffer_.get(); pRenderNode->Viewport_ = Viewport_; pRenderNode->ClearColour_ = ClearColour_; pRenderNode->EnableClearColour_ = EnableClearColour_; pRenderNode->EnableClearDepth_ = EnableClearDepth_; pRenderNode->EnableClearStencil_ = EnableClearStencil_; pFrame->addRenderNode( pRenderNode ); }
////////////////////////////////////////////////////////////////////////// // bind void ScnViewComponent::bind( RsFrame* pFrame, RsRenderSort Sort ) { RsContext* pContext = pFrame->getContext(); // Calculate the viewport. BcF32 Width = static_cast< BcF32 >( pContext->getWidth() ); BcF32 Height = static_cast< BcF32 >( pContext->getHeight() ); // If we're using a render target, we want to use it for dimensions. if( RenderTarget_.isValid() ) { Width = static_cast< BcF32 >( RenderTarget_->getWidth() ); Height = static_cast< BcF32 >( RenderTarget_->getHeight() ); } const BcF32 ViewWidth = Width_ * Width; const BcF32 ViewHeight = Height_ * Height; const BcF32 Aspect = ViewWidth / ViewHeight; // Setup the viewport. Viewport_.viewport( static_cast< BcU32 >( X_ * Width ), static_cast< BcU32 >( Y_ * Height ), static_cast< BcU32 >( ViewWidth ), static_cast< BcU32 >( ViewHeight ), Near_, Far_ ); // Setup matrices in view uniform block. if( ViewUniformBuffer_->lock() ) { // Create appropriate projection matrix. if( HorizontalFOV_ > 0.0f ) { ViewUniformBlock_.ProjectionTransform_.perspProjectionHorizontal( HorizontalFOV_, Aspect, Near_, Far_ ); } else { ViewUniformBlock_.ProjectionTransform_.perspProjectionVertical( VerticalFOV_, 1.0f / Aspect, Near_, Far_ ); } ViewUniformBlock_.InverseProjectionTransform_ = ViewUniformBlock_.ProjectionTransform_; ViewUniformBlock_.InverseProjectionTransform_.inverse(); // Setup view matrix. ViewUniformBlock_.InverseViewTransform_ = getParentEntity()->getWorldMatrix(); ViewUniformBlock_.ViewTransform_ = ViewUniformBlock_.InverseViewTransform_; ViewUniformBlock_.ViewTransform_.inverse(); // Clip transform. ViewUniformBlock_.ClipTransform_ = ViewUniformBlock_.ViewTransform_ * ViewUniformBlock_.ProjectionTransform_; ViewUniformBuffer_->unlock(); } // Build frustum planes. // TODO: revisit this later as we don't need to do it I don't think. FrustumPlanes_[ 0 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] + ViewUniformBlock_.ClipTransform_[0][0] ), ( ViewUniformBlock_.ClipTransform_[1][3] + ViewUniformBlock_.ClipTransform_[1][0] ), ( ViewUniformBlock_.ClipTransform_[2][3] + ViewUniformBlock_.ClipTransform_[2][0] ), ( ViewUniformBlock_.ClipTransform_[3][3] + ViewUniformBlock_.ClipTransform_[3][0]) ); FrustumPlanes_[ 1 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][0] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][0] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][0] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][0] ) ); FrustumPlanes_[ 2 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] + ViewUniformBlock_.ClipTransform_[0][1] ), ( ViewUniformBlock_.ClipTransform_[1][3] + ViewUniformBlock_.ClipTransform_[1][1] ), ( ViewUniformBlock_.ClipTransform_[2][3] + ViewUniformBlock_.ClipTransform_[2][1] ), ( ViewUniformBlock_.ClipTransform_[3][3] + ViewUniformBlock_.ClipTransform_[3][1] ) ); FrustumPlanes_[ 3 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][1] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][1] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][1] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][1] ) ); FrustumPlanes_[ 4 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] - ViewUniformBlock_.ClipTransform_[0][2] ), ( ViewUniformBlock_.ClipTransform_[1][3] - ViewUniformBlock_.ClipTransform_[1][2] ), ( ViewUniformBlock_.ClipTransform_[2][3] - ViewUniformBlock_.ClipTransform_[2][2] ), ( ViewUniformBlock_.ClipTransform_[3][3] - ViewUniformBlock_.ClipTransform_[3][2] ) ); FrustumPlanes_[ 5 ] = MaPlane( ( ViewUniformBlock_.ClipTransform_[0][3] ), ( ViewUniformBlock_.ClipTransform_[1][3] ), ( ViewUniformBlock_.ClipTransform_[2][3] ), ( ViewUniformBlock_.ClipTransform_[3][3] ) ); // Normalise frustum planes. for ( BcU32 i = 0; i < 6; ++i ) { MaVec3d Normal = FrustumPlanes_[ i ].normal(); BcF32 Scale = 1.0f / -Normal.magnitude(); FrustumPlanes_[ i ] = MaPlane( FrustumPlanes_[ i ].normal().x() * Scale, FrustumPlanes_[ i ].normal().y() * Scale, FrustumPlanes_[ i ].normal().z() * Scale, FrustumPlanes_[ i ].d() * Scale ); } // Set render target. if( RenderTarget_.isValid() ) { RenderTarget_->bind( pFrame ); } else { pFrame->setRenderTarget( NULL ); } // Set viewport. pFrame->setViewport( Viewport_ ); }