////////////////////////////////////////////////////////////////////////// // updateBullets void GaBulletProcessor::updateBullets(const ScnComponentList& Components) { float dt = SysKernel::pImpl()->getFrameTime(); static float Time = 0.0f; Time += dt; // Iterate over all the ships. for (BcU32 Idx = 0; Idx < Components.size(); ++Idx) { auto Component = Components[Idx]; BcAssert(Component->isTypeOf< GaBulletComponent >()); auto* ShipComponent = static_cast< GaBulletComponent* >(Component.get()); MaVec3d movement(ShipComponent->Direction_); movement.normalise(); movement.x(movement.x() * ShipComponent->Speed_); movement.z(movement.z() * ShipComponent->Speed_); MaVec3d oldPos = ShipComponent->getParentEntity()->getWorldPosition(); MaVec3d newPos = oldPos + movement * dt; ShipComponent->getParentEntity()->setWorldPosition(newPos); if ((newPos.x() < MinConstraint_.x()) || (newPos.x() > MaxConstraint_.x()) || (newPos.z() < MinConstraint_.z()) || (newPos.z() > MaxConstraint_.z())) { ScnCore::pImpl()->removeEntity(ShipComponent->getParentEntity()); } } }
////////////////////////////////////////////////////////////////////////// // addPrimitive void ScnCanvasComponent::addPrimitive( RsTopologyType Type, ScnCanvasComponentVertex* pVertices, BcU32 NoofVertices, BcU32 Layer, BcBool UseMatrixStack ) { BcAssertMsg( MaterialComponent_.isValid(), "ScnCanvasComponent: Material component has not been set!" ); // Check if the vertices are owned by us, if not copy in. if( pVertices < pVertices_ || pVertices_ >= pVerticesEnd_ ) { ScnCanvasComponentVertex* pNewVertices = allocVertices( NoofVertices ); if( pNewVertices != NULL ) { BcMemCopy( pNewVertices, pVertices, sizeof( ScnCanvasComponentVertex ) * NoofVertices ); pVertices = pNewVertices; } } // Matrix stack. if( UseMatrixStack == BcTrue && IsIdentity_ == BcFalse ) { MaMat4d Matrix = getMatrix(); for( BcU32 Idx = 0; Idx < NoofVertices; ++Idx ) { ScnCanvasComponentVertex* pVertex = &pVertices[ Idx ]; MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix; pVertex->X_ = Vertex.x(); pVertex->Y_ = Vertex.y(); pVertex->Z_ = Vertex.z(); } } // TODO: If there was a previous primitive which we can marge into, attempt to. BcU32 VertexIndex = convertVertexPointerToIndex( pVertices ); ScnCanvasComponentPrimitiveSection PrimitiveSection = { Type, VertexIndex, NoofVertices, Layer, MaterialComponent_, nullptr }; PrimitiveSectionList_.push_back( PrimitiveSection ); LastPrimitiveSection_ = (BcU32)PrimitiveSectionList_.size() - 1; }
////////////////////////////////////////////////////////////////////////// // updateBullets void GaBulletProcessor::bulletCollisions(const ScnComponentList& Components) { float dt = SysKernel::pImpl()->getFrameTime(); static float Time = 0.0f; Time += dt; // Iterate over all the ships. for (BcU32 Idx = 0; Idx < Components.size(); ++Idx) { auto Component = Components[Idx]; BcAssert(Component->isTypeOf< GaBulletComponent >()); auto* BulletComponent = static_cast< GaBulletComponent* >(Component.get()); MaVec3d position = BulletComponent->getParentEntity()->getWorldPosition(); for (BcU32 Idx2 = 0; Idx2 < Ships_.size(); ++Idx2) { auto* Ship = Ships_[Idx2]; if (Ship == BulletComponent->Ship_) continue; MaVec3d shipPos = Ship->getParentEntity()->getWorldPosition(); MaVec3d dif = position - shipPos; dif.y(0); float distance = dif.magnitude(); if (distance < 5.0f) { if (BulletComponent->ExplodeSounds_.size() > 0) { auto Emitter = BulletComponent->getComponentByType< ScnSoundEmitterComponent >(); if (Emitter) { Emitter->playOneShot(BulletComponent->ExplodeSounds_[BcRandom::Global.randRange(0, BulletComponent->ExplodeSounds_.size() - 1)]); } } if (!Ship->IsPlayer()){ ScnCore::pImpl()->removeEntity(Ship->getParentEntity()); BulletComponent->Ship_->addScore(100); ScnCore::pImpl()->removeEntity(BulletComponent->getParentEntity()); } else { GaTitleProcessor::pImpl()->showTitle(); GaShipProcessor::pImpl()->removePlayer(Ship); ScnCore::pImpl()->removeEntity(BulletComponent->getParentEntity()->getParentEntity()); } } }/**/ } }
////////////////////////////////////////////////////////////////////////// // classify MaAABB::eClassify MaAABB::classify( const MaAABB& AABB ) const { BcU32 PointsInside = 0; for( BcU32 i = 0; i < 8; ++i ) { MaVec3d Point = AABB.corner( i ); if( ( Point.x() >= Min_.x() && Point.x() <= Max_.x() ) && ( Point.y() >= Min_.y() && Point.y() <= Max_.y() ) && ( Point.z() >= Min_.z() && Point.z() <= Max_.z() ) ) { PointsInside++; } } if( PointsInside == 8 ) { return bcBC_INSIDE; } if( PointsInside > 0 ) { return bcBC_SPANNING; } return bcBC_OUTSIDE; }
//////////////////////////////////////////////////////////////////////////////// // pointOnNode BcBool MaBSPTree::pointOnNode( const MaVec3d& Point, MaBSPNode* pNode ) { // Check if point is coincident. if( pNode->Plane_.classify( Point, 1e-3f ) != MaPlane::bcPC_COINCIDING ) { return BcFalse; } // if( pNode->Vertices_.size() == 2 ) { // If we only have 2 verts, test we are on the defining line. MaVec3d Origin = pNode->Vertices_[ 0 ]; MaVec3d Direction = pNode->Vertices_[ 1 ] - pNode->Vertices_[ 0 ]; MaVec3d Vector = Point - Origin; BcF32 T = Direction.dot( Vector ); // Check its on the line. return ( T >= 0.0f ) && ( T <= 1.0f ); } else { BcS32 Sign = 0; for( BcU32 Idx = 0; Idx < pNode->Vertices_.size(); ++Idx ) { const MaVec3d& PointA = pNode->Vertices_[ Idx ]; const MaVec3d& PointB = pNode->Vertices_[ ( Idx + 1 ) % pNode->Vertices_.size() ]; const MaVec3d AffineSegment = PointB - PointA; const MaVec3d AffinePoint = Point - PointA; BcF32 K = AffineSegment.dot( AffinePoint ); BcS32 KSign = BcAbs( K ) > 1e-3f ? static_cast< BcS32 >( K / BcAbs( K ) ) : 0; if( Sign == 0 ) { Sign = KSign; } else if( KSign != Sign ) { return BcFalse; } } return BcTrue; } }
////////////////////////////////////////////////////////////////////////// // getWorldPosition void ScnViewComponent::getWorldPosition( const MaVec2d& ScreenPosition, MaVec3d& Near, MaVec3d& Far ) const { // TODO: Take normalised screen coordinates. MaVec2d Screen = ScreenPosition - MaVec2d( static_cast<BcF32>( Viewport_.x() ), static_cast<BcF32>( Viewport_.y() ) ); const MaVec2d RealScreen( ( Screen.x() / Viewport_.width() ) * 2.0f - 1.0f, ( Screen.y() / Viewport_.height() ) * 2.0f - 1.0f ); Near.set( RealScreen.x(), -RealScreen.y(), 0.0f ); Far.set( RealScreen.x(), -RealScreen.y(), 1.0f ); Near = Near * ViewUniformBlock_.InverseProjectionTransform_; Far = Far * ViewUniformBlock_.InverseProjectionTransform_; if( ViewUniformBlock_.ProjectionTransform_[3][3] == 0.0f ) { Near *= Viewport_.zNear(); Far *= Viewport_.zFar(); } Near = Near * ViewUniformBlock_.InverseViewTransform_; Far = Far * ViewUniformBlock_.InverseViewTransform_; }
////////////////////////////////////////////////////////////////////////// // drawLine3d void ScnCanvasComponent::drawLine3d( const MaVec3d& PointA, const MaVec3d& PointB, const RsColour& Colour, BcU32 Layer ) { ScnCanvasComponentVertex* pVertices = allocVertices( 2 ); ScnCanvasComponentVertex* pFirstVertex = pVertices; // Only draw if we can allocate vertices. if( pVertices != NULL ) { // Now copy in data. BcU32 ABGR = Colour.asABGR(); pVertices->X_ = PointA.x(); pVertices->Y_ = PointA.y(); pVertices->Z_ = PointA.z(); pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = PointB.x(); pVertices->Y_ = PointB.y(); pVertices->Z_ = PointB.z(); pVertices->ABGR_ = ABGR; // Add primitive. addPrimitive( rsPT_LINELIST, pFirstVertex, 2, Layer, BcTrue ); } }
void MaAABB::expandBy( const MaVec3d& Point ) { Min_.x( BcMin( Min_.x(), Point.x() ) ); Min_.y( BcMin( Min_.y(), Point.y() ) ); Min_.z( BcMin( Min_.z(), Point.z() ) ); Max_.x( BcMax( Max_.x(), Point.x() ) ); Max_.y( BcMax( Max_.y(), Point.y() ) ); Max_.z( BcMax( Max_.z(), Point.z() ) ); }
////////////////////////////////////////////////////////////////////////// // classify MaAABB::eClassify MaAABB::classify( const MaVec3d& Point ) const { if( ( Point.x() >= Min_.x() && Point.x() <= Max_.x() ) && ( Point.y() >= Min_.y() && Point.y() <= Max_.y() ) && ( Point.z() >= Min_.z() && Point.z() <= Max_.z() ) ) { return bcBC_INSIDE; } return bcBC_OUTSIDE; }
////////////////////////////////////////////////////////////////////////// // drawLine void ScnDebugRenderComponent::drawLine( const MaVec3d& PointA, const MaVec3d& PointB, const RsColour& Colour, BcU32 Layer ) { ScnDebugRenderComponentVertex* pVertices = allocVertices( 2 ); ScnDebugRenderComponentVertex* pFirstVertex = pVertices; // Only draw if we can allocate vertices. if( pVertices != NULL ) { // Now copy in data. BcU32 ABGR = Colour.asABGR(); pVertices->X_ = PointA.x(); pVertices->Y_ = PointA.y(); pVertices->Z_ = PointA.z(); pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = PointB.x(); pVertices->Y_ = PointB.y(); pVertices->Z_ = PointB.z(); pVertices->ABGR_ = ABGR; // Quickly check last primitive. BcBool AddNewPrimitive = BcTrue; if( LastPrimitiveSection_ != BcErrorCode ) { ScnDebugRenderComponentPrimitiveSection& PrimitiveSection = PrimitiveSectionList_[ LastPrimitiveSection_ ]; // If the last primitive was the same type as ours we can append to it. // NOTE: Need more checks here later. if( PrimitiveSection.Type_ == rsPT_LINELIST && PrimitiveSection.Layer_ == Layer && PrimitiveSection.MaterialComponent_ == MaterialComponent_ ) { PrimitiveSection.NoofVertices_ += 2; AddNewPrimitive = BcFalse; } } // Add primitive. if( AddNewPrimitive == BcTrue ) { addPrimitive( rsPT_LINELIST, pFirstVertex, 2, Layer, BcTrue ); } } }
////////////////////////////////////////////////////////////////////////// // drawGrid void ScnDebugRenderComponent::drawGrid( const MaVec3d& Position, const MaVec3d& Size, BcF32 StepSize, BcF32 SubDivideMultiple, BcU32 Layer ) { BcU32 NoofAxis = ( Size.x() > 0 ? 1 : 0 ) + ( Size.y() > 0 ? 1 : 0 ) + ( Size.z() > 0 ? 1 : 0 ); BcAssertMsg( NoofAxis == 2, "Only supports 2 axis in the grid!" ); // Determine which axis to draw along. MaVec3d XAxis; MaVec3d YAxis; BcF32 XSize = 0.0f; BcF32 YSize = 0.0f; if( Size.x() > 0.0f ) { XAxis = MaVec3d( Size.x(), 0.0f, 0.0f ); XSize = Size.x(); if( Size.y() > 0.0f ) { YAxis = MaVec3d( 0.0f, Size.y(), 0.0f ); YSize = Size.y(); } else { YAxis = MaVec3d( 0.0f, 0.0f, Size.z() ); YSize = Size.z(); } } else { XAxis = MaVec3d( 0.0f, Size.y(), 0.0f ); YAxis = MaVec3d( 0.0f, 0.0f, Size.z() ); XSize = Size.y(); YSize = Size.z(); } // Normalise. XAxis.normalise(); YAxis.normalise(); while( StepSize < XSize && StepSize < YSize ) { // Draw grid. for( BcF32 X = 0.0f; X <= XSize; X += StepSize ) { MaVec3d A1( Position + ( XAxis * X ) + ( YAxis * YSize ) ); MaVec3d B1( Position + ( XAxis * X ) + ( YAxis * -YSize ) ); MaVec3d A2( Position + ( XAxis * -X ) + ( YAxis * YSize ) ); MaVec3d B2( Position + ( XAxis * -X ) + ( YAxis * -YSize ) ); drawLine( A1, B1, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer ); drawLine( A2, B2, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer ); } for( BcF32 Y = 0.0f; Y <= YSize; Y += StepSize ) { MaVec3d A1( Position + ( XAxis * YSize ) + ( YAxis * Y ) ); MaVec3d B1( Position + ( XAxis * -YSize ) + ( YAxis * Y ) ); MaVec3d A2( Position + ( XAxis * YSize ) + ( YAxis * -Y ) ); MaVec3d B2( Position + ( XAxis * -YSize ) + ( YAxis * -Y ) ); drawLine( A1, B1, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer ); drawLine( A2, B2, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer ); } StepSize *= SubDivideMultiple; } }
////////////////////////////////////////////////////////////////////////// // drawSprite void ScnCanvasComponent::drawSprite( const MaVec2d& Position, const MaVec2d& Size, BcU32 TextureIdx, const RsColour& Colour, BcU32 Layer ) { ScnCanvasComponentVertex* pVertices = allocVertices( 6 ); ScnCanvasComponentVertex* pFirstVertex = pVertices; const MaVec2d CornerA = Position; const MaVec2d CornerB = Position + Size; const ScnRect Rect = DiffuseTexture_.isValid() ? DiffuseTexture_->getRect( TextureIdx ) : ScnRect(); // Only draw if we can allocate vertices. if( pVertices != NULL ) { // Now copy in data. BcU32 ABGR = Colour.asABGR(); pVertices->X_ = CornerA.x(); pVertices->Y_ = CornerA.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_; pVertices->V_ = Rect.Y_; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerB.x(); pVertices->Y_ = CornerA.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_ + Rect.W_; pVertices->V_ = Rect.Y_; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerA.x(); pVertices->Y_ = CornerB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_; pVertices->V_ = Rect.Y_ + Rect.H_; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerA.x(); pVertices->Y_ = CornerB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_; pVertices->V_ = Rect.Y_ + Rect.H_; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerB.x(); pVertices->Y_ = CornerA.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_ + Rect.W_; pVertices->V_ = Rect.Y_; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerB.x(); pVertices->Y_ = CornerB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = Rect.X_ + Rect.W_; pVertices->V_ = Rect.Y_ + Rect.H_; pVertices->ABGR_ = ABGR; // Quickly check last primitive. BcBool AddNewPrimitive = BcTrue; if( LastPrimitiveSection_ != BcErrorCode ) { ScnCanvasComponentPrimitiveSection& PrimitiveSection = PrimitiveSectionList_[ LastPrimitiveSection_ ]; // If the last primitive was the same type as ours we can append to it. // NOTE: Need more checks here later. if( PrimitiveSection.Type_ == RsTopologyType::TRIANGLE_LIST && PrimitiveSection.Layer_ == Layer && PrimitiveSection.MaterialComponent_ == MaterialComponent_ ) { PrimitiveSection.NoofVertices_ += 6; // Matrix stack. // TODO: Factor into a seperate function. if( IsIdentity_ == BcFalse ) { MaMat4d Matrix = getMatrix(); for( BcU32 Idx = 0; Idx < 6; ++Idx ) { ScnCanvasComponentVertex* pVertex = &pFirstVertex[ Idx ]; MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix; pVertex->X_ = Vertex.x(); pVertex->Y_ = Vertex.y(); pVertex->Z_ = Vertex.z(); pVertex->W_ = 1.0f; } } AddNewPrimitive = BcFalse; } } // Add primitive. if( AddNewPrimitive == BcTrue ) { addPrimitive( RsTopologyType::TRIANGLE_LIST, pFirstVertex, 6, Layer, BcTrue ); } } }
////////////////////////////////////////////////////////////////////////// // drawLine void ScnCanvasComponent::drawLine( const MaVec2d& PointA, const MaVec2d& PointB, const RsColour& Colour, BcU32 Layer ) { ScnCanvasComponentVertex* pVertices = allocVertices( 2 ); ScnCanvasComponentVertex* pFirstVertex = pVertices; // Only draw if we can allocate vertices. if( pVertices != NULL ) { // Now copy in data. BcU32 ABGR = Colour.asABGR(); pVertices->X_ = PointA.x(); pVertices->Y_ = PointA.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = PointB.x(); pVertices->Y_ = PointB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->ABGR_ = ABGR; // Quickly check last primitive. BcBool AddNewPrimitive = BcTrue; if( LastPrimitiveSection_ != BcErrorCode ) { ScnCanvasComponentPrimitiveSection& PrimitiveSection = PrimitiveSectionList_[ LastPrimitiveSection_ ]; // If the last primitive was the same type as ours we can append to it. // NOTE: Need more checks here later. if( PrimitiveSection.Type_ == RsTopologyType::LINE_LIST && PrimitiveSection.Layer_ == Layer && PrimitiveSection.MaterialComponent_ == MaterialComponent_ ) { PrimitiveSection.NoofVertices_ += 2; // Matrix stack. // TODO: Factor into a seperate function. if( IsIdentity_ == BcFalse ) { MaMat4d Matrix = getMatrix(); for( BcU32 Idx = 0; Idx < 2; ++Idx ) { ScnCanvasComponentVertex* pVertex = &pFirstVertex[ Idx ]; MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix; pVertex->X_ = Vertex.x(); pVertex->Y_ = Vertex.y(); pVertex->Z_ = Vertex.z(); pVertices->W_ = 1.0f; } } AddNewPrimitive = BcFalse; } } // Add primitive. if( AddNewPrimitive == BcTrue ) { addPrimitive( RsTopologyType::LINE_LIST, pFirstVertex, 2, Layer, BcTrue ); } } }
////////////////////////////////////////////////////////////////////////// // drawEllipsoid void ScnDebugRenderComponent::drawEllipsoid( const MaVec3d& Position, const MaVec3d& Size, const RsColour& Colour, BcU32 Layer ) { // Draw outer circles for all axis. BcU32 LOD = 16; BcF32 Angle = 0.0f; BcF32 AngleInc = ( BcPI * 2.0f ) / BcF32( LOD ); // Draw axis lines. for( BcU32 i = 0; i < LOD; ++i ) { MaVec2d PosA( BcCos( Angle ), -BcSin( Angle ) ); MaVec2d PosB( BcCos( Angle + AngleInc ), -BcSin( Angle + AngleInc ) ); MaVec3d XAxisA = MaVec3d( 0.0f, PosA.x() * Size.y(), PosA.y() * Size.z() ); MaVec3d YAxisA = MaVec3d( PosA.x() * Size.x(), 0.0f, PosA.y() * Size.z() ); MaVec3d ZAxisA = MaVec3d( PosA.x() * Size.x(), PosA.y() * Size.y(), 0.0f ); MaVec3d XAxisB = MaVec3d( 0.0f, PosB.x() * Size.y(), PosB.y() * Size.z() ); MaVec3d YAxisB = MaVec3d( PosB.x() * Size.x(), 0.0f, PosB.y() * Size.z() ); MaVec3d ZAxisB = MaVec3d( PosB.x() * Size.x(), PosB.y() * Size.y(), 0.0f ); drawLine( XAxisA + Position, XAxisB + Position, Colour, 0 ); drawLine( YAxisA + Position, YAxisB + Position, Colour, 0 ); drawLine( ZAxisA + Position, ZAxisB + Position, Colour, 0 ); Angle += AngleInc; } // Draw a cross down centre. MaVec3d XAxis = MaVec3d( Size.x(), 0.0f, 0.0f ); MaVec3d YAxis = MaVec3d( 0.0f, Size.y(), 0.0f ); MaVec3d ZAxis = MaVec3d( 0.0f, 0.0f, Size.z() ); drawLine( Position - XAxis, Position + XAxis, Colour, Layer ); drawLine( Position - YAxis, Position + YAxis, Colour, Layer ); drawLine( Position - ZAxis, Position + ZAxis, Colour, Layer ); }
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 ); }
void GaGameComponent::onClick( OsEventInputMouse Event ) { GaUnitComponent* SelectedUnit = nullptr; GaVec3d SelectedLocation; BcBool SelectedValidLocation = BcFalse; GaUnitCommand Command; // Determine selection location. { MaVec3d NearPos, FarPos; Camera_->getWorldPosition( MaVec2d( Event.MouseX_, Event.MouseY_ ), NearPos, FarPos ); MaPlane GroundPlane; GroundPlane.fromPointNormal( MaVec3d( 0.0f, 0.0f, 0.0f ), MaVec3d( 0.0f, 1.0f, 0.0f ) ); auto Dir = ( FarPos - NearPos ).normal(); BcF32 Distance = 0.0f; MaVec3d Intersection; if( GroundPlane.lineIntersection( NearPos, FarPos, Distance, Intersection ) ) { SelectedLocation = GaVec3d( Intersection.x(), Intersection.y(), Intersection.z() ); SelectedValidLocation = BcTrue; } } // Determine selection unit. for( auto* Unit : Units_ ) { if( Unit->isSelectable() ) { MaVec3d NearPos, FarPos; Camera_->getWorldPosition( MaVec2d( Event.MouseX_, Event.MouseY_ ), NearPos, FarPos ); auto SpatialComponent = Unit->getComponentByType< ScnSpatialComponent >(); if( SpatialComponent != nullptr ) { auto AABB = SpatialComponent->getAABB(); MaVec3d Intersection; if( AABB.lineIntersect( NearPos, FarPos, &Intersection, nullptr ) ) { SelectedUnit = Unit; } } } } if( SelectedCommand_.Type_ == GaUnitCommandType::INVALID ) { // No command and left click, select. if( Event.ButtonCode_ == 0 ) { if( SelectedUnit != nullptr ) { SelectedUnitIDs_.clear(); SelectedUnitIDs_.push_back( SelectedUnit->getID() ); SelectedCommand_ = GaUnitCommand(); } } } else { Command = SelectedCommand_; Command.UnitID_ = SelectedUnit ? SelectedUnit->getID() : BcErrorCode; Command.Location_ = SelectedLocation; } // If right click, move. if( Event.ButtonCode_ == 1 ) { SelectedCommand_ = GaUnitCommand(); if( SelectedValidLocation || SelectedUnit ) { Command.Type_ = GaUnitCommandType::MOVE; Command.Location_ = SelectedLocation; Command.UnitID_ = SelectedUnit ? SelectedUnit->getID() : BcErrorCode; } } // If we have a command. if( Command.Type_ != GaUnitCommandType::INVALID ) { // Move is a special case since formation is predetermined. if( Command.Type_ == GaUnitCommandType::MOVE ) { // Find midpoint. GaVec3d Midpoint( 0.0f, 0.0f, 0.0f ); GaReal NoofUnits = 0; for( auto UnitID : SelectedUnitIDs_ ) { auto* Unit = getUnit( UnitID ); if( Unit ) { Midpoint += Unit->getState().Position_; NoofUnits += 1.0f; } } if( NoofUnits > 0.0f ) { Midpoint /= NoofUnits; } // TODO: Position them in formation. // Send all units to offsets around this position. for( auto UnitID : SelectedUnitIDs_ ) { auto* Unit = getUnit( UnitID ); if( Unit ) { auto Centre = Command.Location_; auto NewCommand = Command; NewCommand.Location_ = ( Unit->getState().Position_ - Midpoint ) + Centre; command( Unit, NewCommand ); } } } else { for( auto UnitID : SelectedUnitIDs_ ) { auto* Unit = getUnit( UnitID ); if( Unit ) { Unit->command( Command ); } } } } CommandsDirty_ = BcTrue; }
////////////////////////////////////////////////////////////////////////// // buildTangents void MdlMesh::buildTangents() { MaVec3d* pTan1 = new MaVec3d[ aVertices_.size() * 2 ]; MaVec3d* pTan2 = pTan1 + aVertices_.size(); memset( pTan1, 0, sizeof( MaVec3d ) * aVertices_.size() * 2 ); for ( BcU32 i = 0; i < ( aIndices_.size() / 3 ); ++i ) { BcU32 TA = aIndices_[ ( i * 3 ) + 0 ].iVertex_; BcU32 TB = aIndices_[ ( i * 3 ) + 1 ].iVertex_; BcU32 TC = aIndices_[ ( i * 3 ) + 2 ].iVertex_; MdlVertex& VertA = aVertices_[ TA ]; MdlVertex& VertB = aVertices_[ TB ]; MdlVertex& VertC = aVertices_[ TC ]; MaVec3d VertPosA = VertA.Position_; MaVec3d VertPosB = VertB.Position_; MaVec3d VertPosC = VertC.Position_; MaVec2d VertUVA = VertA.UV_; MaVec2d VertUVB = VertB.UV_; MaVec2d VertUVC = VertC.UV_; BcF32 X1 = VertPosB.x() - VertPosA.x(); BcF32 X2 = VertPosC.x() - VertPosA.x(); BcF32 Y1 = VertPosB.y() - VertPosA.y(); BcF32 Y2 = VertPosC.y() - VertPosA.y(); BcF32 Z1 = VertPosB.z() - VertPosA.z(); BcF32 Z2 = VertPosC.z() - VertPosA.z(); BcF32 S1 = VertUVB.x() - VertUVA.x(); BcF32 S2 = VertUVC.x() - VertUVA.x(); BcF32 T1 = VertUVB.y() - VertUVA.y(); BcF32 T2 = VertUVC.y() - VertUVA.y(); BcF32 InvR = ( S1 * T2 - S2 * T1 ); BcF32 R = 1.0f / InvR; // Validation so it doesn't break everything, just set to a dummy value. if( BcAbs( InvR ) < 1e-6f ) { R = 0.0f; } MaVec3d SDir( ( T2 * X1 - T1 * X2 ) * R, ( T2 * Y1 - T1 * Y2 ) * R, ( T2 * Z1 - T1 * Z2 ) * R ); MaVec3d TDir( ( S1 * X2 - S2 * X1 ) * R, ( S1 * Y2 - S2 * Y1 ) * R, ( S1 * Z2 - S2 * Z1 ) * R ); pTan1[ TA ] += SDir; pTan1[ TB ] += SDir; pTan1[ TC ] += SDir; pTan2[ TA ] += TDir; pTan2[ TB ] += TDir; pTan2[ TC ] += TDir; } for ( BcU32 i = 0; i < aVertices_.size(); ++i ) { MdlVertex& Vert = aVertices_[ i ]; MaVec3d Tangent; const MaVec3d N = Vert.Normal_; const MaVec3d& T = pTan1[ i ]; Tangent = ( T - N * N.dot( T ) ); Tangent.normalise(); // Calculate handedness BcF32 W = ( N.cross( T ).dot( pTan2[ i ] ) < 0.0f ) ? -1.0f : 1.0f; if ( W < 0.0f ) { Tangent = -Tangent; } Vert.bTangent_ = BcTrue; Vert.Tangent_ = Tangent; // Validate, and create a dummy value. BcF32 Mag = Tangent.magnitude(); if( BcAbs( Mag - 1.0f ) > 0.0001f ) { Vert.Tangent_.set( 0.0f, 0.0f, 0.0f ); } } delete[] pTan1; }
////////////////////////////////////////////////////////////////////////// // 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_ ); }
////////////////////////////////////////////////////////////////////////// // update //virtual void GaEnemyComponent::update( BcF32 Tick ) { // Find move vector. BcF32 MoveSpeed = 2.0f; MaVec3d MoveVector; PulseTimer_ += Tick; // Set direction and handle if we need to change direction. MaVec3d Position = getParentEntity()->getWorldPosition(); MoveVector = Direction_; BcBSPPointInfo BSPPointInfo; if( BSP_->lineIntersection( Position, Position + Direction_ * 256.0f, &BSPPointInfo ) ) { if( BSPPointInfo.Distance_ < 1.0f ) { // New direction. Direction_ = Direction_.reflect( BSPPointInfo.Plane_.normal() ); // Belt & braces: it will become denormalised over time. Direction_.normalise(); // Clamp position (this is to prevent wandering, if angles aren't sitting on an integer, expect weirdness). Position = MaVec3d( BcRound( Position.x() ), BcRound( Position.y() ), BcRound( Position.z() ) ); } } BcF32 PulseTime = 2.0f; if( BSP_->canSeePlayer( Position ) ) { BcPrintf( "I CAN SEE UUU\n" ); PulseTime = 0.5f; IsTargetting_ = BcTrue; TargetTimer_ -= Tick; } else { IsTargetting_ = BcFalse; TargetTimer_ = 3.0f; } // Pulse. if( PulseTimer_ > PulseTime ) { Pressure_->setSample( Position, 0.5f ); PulseTimer_ = 0.0f; } // Shoot player. if( IsTargetting_ && TargetTimer_ < 0.0f ) { BSP_->killPlayer(); } // Set the move. if( !IsTargetting_ ) { MaVec3d AppliedMoveVector = MoveVector; AppliedMoveVector.z( 0.0f ); AppliedMoveVector = AppliedMoveVector.normal() * MoveSpeed; Pawn_->setMove( AppliedMoveVector ); } else { Pawn_->setMove( MaVec3d( 0.0f, 0.0f, 0.0f ) ); } }
////////////////////////////////////////////////////////////////////////// // lineCast BcBool ScnPhysicsWorldComponent::lineCast( const MaVec3d& A, const MaVec3d& B, MaVec3d& Intersection, MaVec3d& Normal ) { btCollisionWorld::ClosestRayResultCallback HitResult( btVector3( A.x(), A.y(), A.z() ), btVector3( B.x(), B.y(), B.z() ) ); DynamicsWorld_->rayTest( btVector3( A.x(), A.y(), A.z() ), btVector3( B.x(), B.y(), B.z() ), HitResult ); if( HitResult.hasHit() ) { Intersection = MaVec3d( HitResult.m_hitPointWorld.x(), HitResult.m_hitPointWorld.y(), HitResult.m_hitPointWorld.z() ); Normal = MaVec3d( HitResult.m_hitNormalWorld.x(), HitResult.m_hitNormalWorld.y(), HitResult.m_hitNormalWorld.z() ); return BcTrue; } return BcFalse; }