////////////////////////////////////////////////////////////////////////// // update //virtual void GaSpeechBubbleComponent::update( BcF32 Tick ) { Super::update( Tick ); if ( !FontComponent_.isValid() ) { Canvas_ = ParentEntity_->getComponentAnyParentByType< ScnCanvasComponent >(); FontComponent_ = ParentEntity_->getComponentAnyParentByType< ScnFontComponent >(); } if ( !SpeechBubble_.isValid() ) { SpeechBubble_ = ParentEntity_->getComponentByType<ScnSpriteComponent>( BcName( "SpeechBubbleComponent", 0 ) ); } if ( SpeechBubble_.isValid() ) { SpeechBubble_->setColour( RsColour( 1, 1, 1, Visible_ ? 0.8 : 0 ) ); } if ( !TargetEntity_.isValid() ) { // We aren't even gonna bother return; } MaMat4d TextScaleMatrix; //TextScaleMatrix.scale( MaVec4d( 0.04f, 0.04f, 1.0f, 1.0f ) ); TextScaleMatrix.scale( MaVec4d( 1.00f, -1.00f, 1.0f, 1.0f ) ); FontComponent_->setAlphaTestStepping( MaVec2d( 0.4f, 0.45f ) ); if (Visible_) { TimeBeenVisible_ += Tick; if ( TimeBeenVisible_ > VisibleTime_ ) Visible_ = false; //MaMat4d Matrix = getParentEntity()->getWorldMatrix(); //Matrix = Canvas_->popMatrix(); Canvas_->pushMatrix( TextScaleMatrix ); MaVec2d Size; MaVec3d worldPos = TargetEntity_->getWorldPosition(); MaVec2d Position( 0 , 0 ); MaVec2d localPos = SpeechBubble_->getPosition(); localPos = MaVec2d(TargetEntity_->getWorldPosition().x(), -TargetEntity_->getWorldPosition().y() ) + FontOffset_; SpeechBubble_->setPosition( MaVec2d( TargetEntity_->getWorldPosition().x(), TargetEntity_->getWorldPosition().y() ) + SpriteOffset_ ); for( BcU32 Idx = 0; Idx < Text_.size(); ++Idx ) { const auto& Option( Text_[ Idx ] ); const auto Colour = RsColour::BLACK; Size = FontComponent_->drawCentered( Canvas_, localPos + Position, Text_[ Idx ] , Colour, 280 ); Position += MaVec2d( 0.0f, Size.y() ); } Canvas_->popMatrix(); } //Canvas_->pushMatrix( Matrix ); //Canvas_->setMatrix( Matrix ); }
////////////////////////////////////////////////////////////////////////// // drawLineBox void ScnCanvasComponent::drawLineBox( const MaVec2d& CornerA, const MaVec2d& CornerB, const RsColour& Colour, BcU32 Layer ) { // SLOW. drawLine( MaVec2d( CornerA.x(), CornerA.y() ), MaVec2d( CornerB.x(), CornerA.y() ), Colour, Layer ); drawLine( MaVec2d( CornerB.x(), CornerA.y() ), MaVec2d( CornerB.x(), CornerB.y() ), Colour, Layer ); drawLine( MaVec2d( CornerB.x(), CornerB.y() ), MaVec2d( CornerA.x(), CornerB.y() ), Colour, Layer ); drawLine( MaVec2d( CornerA.x(), CornerB.y() ), MaVec2d( CornerA.x(), CornerA.y() ), Colour, Layer ); }
////////////////////////////////////////////////////////////////////////// // getScreenPosition MaVec2d ScnViewComponent::getScreenPosition( const MaVec3d& WorldPosition ) const { MaVec4d ScreenSpace = MaVec4d( WorldPosition, 1.0f ) * ViewUniformBlock_.ClipTransform_; MaVec2d ScreenPosition = MaVec2d( ScreenSpace.x() / ScreenSpace.w(), -ScreenSpace.y() / ScreenSpace.w() ); BcF32 HalfW = BcF32( Viewport_.width() ) * 0.5f; BcF32 HalfH = BcF32( Viewport_.height() ) * 0.5f; return MaVec2d( ( ScreenPosition.x() * HalfW ), ( ScreenPosition.y() * HalfH ) ); }
////////////////////////////////////////////////////////////////////////// // drawBox void ScnCanvasComponent::drawBox( const MaVec2d& CornerA, const MaVec2d& CornerB, const RsColour& Colour, BcU32 Layer ) { ScnCanvasComponentVertex* pVertices = allocVertices( 4 ); ScnCanvasComponentVertex* pFirstVertex = pVertices; // 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_ = 0.0f; pVertices->V_ = 0.0f; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerB.x(); pVertices->Y_ = CornerA.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = 1.0f; pVertices->V_ = 0.0f; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerA.x(); pVertices->Y_ = CornerB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = 0.0f; pVertices->V_ = 1.0f; pVertices->ABGR_ = ABGR; ++pVertices; pVertices->X_ = CornerB.x(); pVertices->Y_ = CornerB.y(); pVertices->Z_ = 0.0f; pVertices->W_ = 1.0f; pVertices->U_ = 1.0f; pVertices->V_ = 1.0f; pVertices->ABGR_ = ABGR; // Add primitive. addPrimitive( RsTopologyType::TRIANGLE_STRIP, pFirstVertex, 4, Layer, 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_; }
////////////////////////////////////////////////////////////////////////// // 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 ); } } }
////////////////////////////////////////////////////////////////////////// // 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; }
//virtual void ScnParticleSystemComponent::render( class ScnViewComponent* pViewComponent, RsFrame* pFrame, RsRenderSort Sort ) { // Wait for update fence. UpdateFence_.wait(); // Grab vertex buffer and flip for next frame to use. TVertexBuffer& VertexBuffer = VertexBuffers_[ CurrentVertexBuffer_ ]; CurrentVertexBuffer_ = 1 - CurrentVertexBuffer_; // Lock vertex buffer. VertexBuffer.pVertexBuffer_->lock(); // Iterate over alive particles, and setup vertex buffer. BcU32 NoofParticlesToRender = 0; ScnParticleVertex* pVertex = VertexBuffer.pVertexArray_; for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx ) { ScnParticle& Particle = pParticleBuffer_[ Idx ]; if( Particle.Alive_ ) { // Half size. const MaVec2d HalfSize = Particle.Scale_ * 0.5f; const BcF32 MaxHalfSize = BcMax( HalfSize.x(), HalfSize.y() ); BcAssert( Particle.TextureIndex_ < UVBounds_.size() ); const MaVec4d& UVBounds( UVBounds_[ Particle.TextureIndex_ ] ); // Crappy rotation implementation :P const BcF32 Radians = Particle.Rotation_; MaVec2d CornerA = MaVec2d( -1.0f, -1.0f ) * HalfSize; MaVec2d CornerB = MaVec2d( 1.0f, -1.0f ) * HalfSize; MaVec2d CornerC = MaVec2d( 1.0f, 1.0f ) * HalfSize; MaVec2d CornerD = MaVec2d( -1.0f, 1.0f ) * HalfSize; if( Radians != NULL ) { MaMat4d Rotation; Rotation.rotation( MaVec3d( 0.0f, 0.0f, Radians ) ); CornerA = CornerA * Rotation; CornerB = CornerB * Rotation; CornerC = CornerC * Rotation; CornerD = CornerD * Rotation; } const BcU32 Colour = Particle.Colour_.asABGR(); // Grab vertices. ScnParticleVertex& VertexA = *pVertex++; ScnParticleVertex& VertexB = *pVertex++; ScnParticleVertex& VertexC = *pVertex++; ScnParticleVertex& VertexD = *pVertex++; ScnParticleVertex& VertexE = *pVertex++; ScnParticleVertex& VertexF = *pVertex++; // VertexA.X_ = Particle.Position_.x(); VertexA.Y_ = Particle.Position_.y(); VertexA.Z_ = Particle.Position_.z(); VertexA.NX_ = CornerA.x(); VertexA.NY_ = CornerA.y(); VertexA.NZ_ = 0.0f; VertexA.U_ = UVBounds.x(); VertexA.V_ = UVBounds.y(); VertexA.RGBA_ = Colour; // VertexB.X_ = Particle.Position_.x(); VertexB.Y_ = Particle.Position_.y(); VertexB.Z_ = Particle.Position_.z(); VertexB.NX_ = CornerB.x(); VertexB.NY_ = CornerB.y(); VertexB.NZ_ = 0.0f; VertexB.U_ = UVBounds.z(); VertexB.V_ = UVBounds.y(); VertexB.RGBA_ = Colour; // VertexC.X_ = Particle.Position_.x(); VertexC.Y_ = Particle.Position_.y(); VertexC.Z_ = Particle.Position_.z(); VertexC.NX_ = CornerC.x(); VertexC.NY_ = CornerC.y(); VertexC.NZ_ = 0.0f; VertexC.U_ = UVBounds.z(); VertexC.V_ = UVBounds.w(); VertexC.RGBA_ = Colour; // VertexD.X_ = Particle.Position_.x(); VertexD.Y_ = Particle.Position_.y(); VertexD.Z_ = Particle.Position_.z(); VertexD.NX_ = CornerC.x(); VertexD.NY_ = CornerC.y(); VertexD.NZ_ = 0.0f; VertexD.U_ = UVBounds.z(); VertexD.V_ = UVBounds.w(); VertexD.RGBA_ = Colour; // VertexE.X_ = Particle.Position_.x(); VertexE.Y_ = Particle.Position_.y(); VertexE.Z_ = Particle.Position_.z(); VertexE.NX_ = CornerD.x(); VertexE.NY_ = CornerD.y(); VertexE.NZ_ = 0.0f; VertexE.U_ = UVBounds.x(); VertexE.V_ = UVBounds.w(); VertexE.RGBA_ = Colour; // VertexF.X_ = Particle.Position_.x(); VertexF.Y_ = Particle.Position_.y(); VertexF.Z_ = Particle.Position_.z(); VertexF.NX_ = CornerA.x(); VertexF.NY_ = CornerA.y(); VertexF.NZ_ = 0.0f; VertexF.U_ = UVBounds.x(); VertexF.V_ = UVBounds.y(); VertexF.RGBA_ = Colour; // ++NoofParticlesToRender; } } // Update and unlock vertex buffer. VertexBuffer.pVertexBuffer_->setNoofUpdateVertices( NoofParticlesToRender * 6 ); VertexBuffer.pVertexBuffer_->unlock(); // Draw particles last. if( NoofParticlesToRender > 0 ) { Sort.Layer_ = 15; // Bind material. if( IsLocalSpace_ ) { const MaMat4d& WorldTransform = getParentEntity()->getWorldMatrix(); MaterialComponent_->setParameter( WorldTransformParam_, WorldTransform ); } else { MaterialComponent_->setParameter( WorldTransformParam_, MaMat4d() ); } // Set material parameters for view. pViewComponent->setMaterialParameters( MaterialComponent_ ); // Bind material component. MaterialComponent_->bind( pFrame, Sort ); // Setup render node. ScnParticleSystemComponentRenderNode* pRenderNode = pFrame->newObject< ScnParticleSystemComponentRenderNode >(); pRenderNode->pPrimitive_ = VertexBuffer.pPrimitive_; pRenderNode->NoofIndices_ = NoofParticlesToRender * 6; // Add to frame. pRenderNode->Sort_ = Sort; pFrame->addRenderNode( pRenderNode ); } }
////////////////////////////////////////////////////////////////////////// // update void GaStructureComponent::update( BcF32 Tick ) { // Get water. auto Water = getParentEntity()->getComponentAnyParentByType< GaWaterComponent >(); // If we have point masses, calculate position. const size_t NoofPointMasses = Physics_->getNoofPointMasses(); if( Physics_->getNoofPointMasses() > 0 ) { // Points with weight. const BcF32 Gravity = 500.0f; for( auto WeightedPoint : WeightedPoints_ ) { Physics_->setPointMassAcceleration( WeightedPoint, MaVec2d( 0.0f, Gravity ) ); } // Points with bouyancy. for( auto BouyantPoint : BouyantPoints_ ) { const auto& PointMass = Physics_->getPointMass( BouyantPoint ); auto WaterPosition = Water->getWaterSurfacePosition( PointMass.CurrPosition_ ); BcF32 Diff = PointMass.CurrPosition_.y() - WaterPosition.y(); if( Diff > 1.0f ) { Physics_->setPointMassAcceleration( BouyantPoint, MaVec2d( 0.0f, -Gravity ) ); } else { Physics_->setPointMassAcceleration( BouyantPoint, MaVec2d( 0.0f, Gravity ) ); } } // Position. MaVec2d Centre( Physics_->getPointMassPosition( 0 ) ); getParentEntity()->setLocalPosition( MaVec3d( Centre, 0.0f ) ); // Rotation. MaVec2d Direction = Centre - Physics_->getPointMassPosition( 1 ); BcF32 Angle = std::atan2f( Direction.x(), Direction.y() ); Sprite_->setRotation( Angle ); if( Timer_ <= CalculatedFireRate_ ) { Timer_ += Tick; } } switch( StructureType_ ) { case GaStructureType::BASE: break; case GaStructureType::TURRET: if( Timer_ >= CalculatedFireRate_ ) { // Find a tentacle. GaTentacleComponent* NearestTentacle = Game_->getNearestTentacle( getParentEntity()->getWorldPosition().xy(), BcFalse ); if( NearestTentacle == nullptr ) { NearestTentacle = Game_->getNearestTentacle( getParentEntity()->getWorldPosition().xy(), BcTrue ); } // Spawn a projectile. if( NearestTentacle && TemplateProjectile_ ) { auto Entity = ScnCore::pImpl()->spawnEntity( ScnEntitySpawnParams( BcName::INVALID, TemplateProjectile_, getParentEntity()->getWorldMatrix(), Game_->getParentEntity() ) ); auto Projectile = Entity->getComponentByType< GaProjectileComponent >(); Projectile->setLevel( Level_ ); Projectile->setTarget( NearestTentacle->getParentEntity() ); Game_->launchProjectile( Projectile ); // Time to spawn! Timer_ -= CalculatedFireRate_; } } break; case GaStructureType::RESOURCE: break; case GaStructureType::POTATO: break; case GaStructureType::MINE: break; } }
//virtual void ScnParticleSystemComponent::render( class ScnViewComponent* pViewComponent, RsFrame* pFrame, RsRenderSort Sort ) { // Wait for update fence. UpdateFence_.wait(); // Grab vertex buffer and flip for next frame to use. TVertexBuffer& VertexBuffer = VertexBuffers_[ CurrentVertexBuffer_ ]; CurrentVertexBuffer_ = 1 - CurrentVertexBuffer_; // Calculate lock size. BcU32 NoofParticlesToRender = 0; for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx ) { ScnParticle& Particle = pParticleBuffer_[ Idx ]; if( Particle.Alive_ ) { ++NoofParticlesToRender; } } // Lock vertex buffer. if( NoofParticlesToRender > 0 ) { UploadFence_.increment(); RsCore::pImpl()->updateBuffer( VertexBuffer.pVertexBuffer_, 0, NoofParticlesToRender * sizeof( ScnParticleVertex ) * 6, RsResourceUpdateFlags::ASYNC, [ this, NoofParticlesToRender ] ( RsBuffer* Buffer, const RsBufferLock& Lock ) { BcU32 NoofParticlesRendered = 0; ScnParticleVertex* pVertex = reinterpret_cast< ScnParticleVertex* >( Lock.Buffer_ ); for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx ) { ScnParticle& Particle = pParticleBuffer_[ Idx ]; if( Particle.Alive_ ) { ++NoofParticlesRendered; // Half size. const MaVec2d HalfSize = Particle.Scale_ * 0.5f; BcAssert( Particle.TextureIndex_ < UVBounds_.size() ); const MaVec4d& UVBounds( UVBounds_[ Particle.TextureIndex_ ] ); // Crappy rotation implementation :P const BcF32 Radians = Particle.Rotation_; MaVec2d CornerA = MaVec2d( -1.0f, -1.0f ) * HalfSize; MaVec2d CornerB = MaVec2d( 1.0f, -1.0f ) * HalfSize; MaVec2d CornerC = MaVec2d( 1.0f, 1.0f ) * HalfSize; MaVec2d CornerD = MaVec2d( -1.0f, 1.0f ) * HalfSize; if( Radians != 0.0f ) { MaMat4d Rotation; Rotation.rotation( MaVec3d( 0.0f, 0.0f, Radians ) ); CornerA = CornerA * Rotation; CornerB = CornerB * Rotation; CornerC = CornerC * Rotation; CornerD = CornerD * Rotation; } const BcU32 Colour = Particle.Colour_.asABGR(); // Grab vertices. ScnParticleVertex& VertexA = *pVertex++; ScnParticleVertex& VertexB = *pVertex++; ScnParticleVertex& VertexC = *pVertex++; ScnParticleVertex& VertexD = *pVertex++; ScnParticleVertex& VertexE = *pVertex++; ScnParticleVertex& VertexF = *pVertex++; // VertexA.X_ = Particle.Position_.x(); VertexA.Y_ = Particle.Position_.y(); VertexA.Z_ = Particle.Position_.z(); VertexA.W_ = 1.0f; VertexA.NX_ = CornerA.x(); VertexA.NY_ = CornerA.y(); VertexA.NZ_ = 0.0f; VertexA.U_ = UVBounds.x(); VertexA.V_ = UVBounds.y(); VertexA.RGBA_ = Colour; // VertexB.X_ = Particle.Position_.x(); VertexB.Y_ = Particle.Position_.y(); VertexB.Z_ = Particle.Position_.z(); VertexB.W_ = 1.0f; VertexB.NX_ = CornerB.x(); VertexB.NY_ = CornerB.y(); VertexB.NZ_ = 0.0f; VertexB.U_ = UVBounds.z(); VertexB.V_ = UVBounds.y(); VertexB.RGBA_ = Colour; // VertexC.X_ = Particle.Position_.x(); VertexC.Y_ = Particle.Position_.y(); VertexC.Z_ = Particle.Position_.z(); VertexC.W_ = 1.0f; VertexC.NX_ = CornerC.x(); VertexC.NY_ = CornerC.y(); VertexC.NZ_ = 0.0f; VertexC.U_ = UVBounds.z(); VertexC.V_ = UVBounds.w(); VertexC.RGBA_ = Colour; // VertexD.X_ = Particle.Position_.x(); VertexD.Y_ = Particle.Position_.y(); VertexD.Z_ = Particle.Position_.z(); VertexD.W_ = 1.0f; VertexD.NX_ = CornerC.x(); VertexD.NY_ = CornerC.y(); VertexD.NZ_ = 0.0f; VertexD.U_ = UVBounds.z(); VertexD.V_ = UVBounds.w(); VertexD.RGBA_ = Colour; // VertexE.X_ = Particle.Position_.x(); VertexE.Y_ = Particle.Position_.y(); VertexE.Z_ = Particle.Position_.z(); VertexE.W_ = 1.0f; VertexE.NX_ = CornerD.x(); VertexE.NY_ = CornerD.y(); VertexE.NZ_ = 0.0f; VertexE.U_ = UVBounds.x(); VertexE.V_ = UVBounds.w(); VertexE.RGBA_ = Colour; // VertexF.X_ = Particle.Position_.x(); VertexF.Y_ = Particle.Position_.y(); VertexF.Z_ = Particle.Position_.z(); VertexF.W_ = 1.0f; VertexF.NX_ = CornerA.x(); VertexF.NY_ = CornerA.y(); VertexF.NZ_ = 0.0f; VertexF.U_ = UVBounds.x(); VertexF.V_ = UVBounds.y(); VertexF.RGBA_ = Colour; } } BcAssert( NoofParticlesRendered == NoofParticlesToRender ); UploadFence_.decrement(); } ); } // Update uniform buffer. if( IsLocalSpace_ ) { VertexBuffer.ObjectUniforms_.WorldTransform_ = getParentEntity()->getWorldMatrix(); } else { VertexBuffer.ObjectUniforms_.WorldTransform_ = MaMat4d(); } // Upload uniforms. RsCore::pImpl()->updateBuffer( VertexBuffer.UniformBuffer_, 0, sizeof( VertexBuffer.ObjectUniforms_ ), RsResourceUpdateFlags::ASYNC, [ this, VertexBuffer ]( RsBuffer* Buffer, const RsBufferLock& Lock ) { BcMemCopy( Lock.Buffer_, &VertexBuffer.ObjectUniforms_, sizeof( VertexBuffer.ObjectUniforms_ ) ); } ); // Draw particles last. if( NoofParticlesToRender > 0 ) { Sort.Layer_ = 15; // Set material parameters for view. pViewComponent->setMaterialParameters( MaterialComponent_ ); // Bind material component. MaterialComponent_->bind( pFrame, Sort ); // Setup render node. ScnParticleSystemComponentRenderNode* pRenderNode = pFrame->newObject< ScnParticleSystemComponentRenderNode >(); pRenderNode->VertexBuffer_ = VertexBuffer.pVertexBuffer_; pRenderNode->VertexDeclaration_ = VertexDeclaration_; pRenderNode->NoofIndices_ = NoofParticlesToRender * 6; // Add to frame. pRenderNode->Sort_ = Sort; pFrame->addRenderNode( pRenderNode ); } }
////////////////////////////////////////////////////////////////////////// // drawSpriteCentered void ScnCanvasComponent::drawSpriteCenteredUp3D( const MaVec3d& Position, const MaVec2d& Size, BcU32 TextureIdx, const RsColour& Colour, BcU32 Layer ) { MaVec3d NewPosition = Position - MaVec3d( Size.x() * 0.5f, 0.0f, Size.y() * 0.5f ); drawSpriteUp3D( NewPosition, Size, TextureIdx, Colour, Layer ); }