////////////////////////////////////////////////////////////////////////// // flipTransform void MdlNode::flipTransform( BcMat4d& Transform ) { Transform.transpose(); Transform[0][2] = -Transform[0][2]; Transform[1][2] = -Transform[1][2]; Transform[2][0] = -Transform[2][0]; Transform[2][1] = -Transform[2][1]; Transform[2][3] = -Transform[2][3]; Transform.transpose(); }
////////////////////////////////////////////////////////////////////////// // bakeTransform void MdlMesh::bakeTransform( const BcMat4d& Transform ) { BcMat4d NrmTransform = Transform; NrmTransform.translation( BcVec3d( 0.0f, 0.0f, 0.0f ) ); for( BcU32 i = 0; i < aVertices_.size(); ++i ) { aVertices_[ i ].Position_ = aVertices_[ i ].Position_ * Transform; aVertices_[ i ].Normal_ = aVertices_[ i ].Normal_ * NrmTransform; aVertices_[ i ].Normal_.normalise(); aVertices_[ i ].Tangent_ = aVertices_[ i ].Tangent_ * NrmTransform; aVertices_[ i ].Tangent_.normalise(); } }
//////////////////////////////////////////////////////////////////////////////// // render //virtual void GaMainGameState::render() { // NEILO HACK: REMOVE. OsClient* pClient = OsCore::pImpl()->getClient( 0 ); RsViewport Viewport( 0, 0, pClient->getWidth(), pClient->getHeight() ); // Render background. Projection_.perspProjectionHorizontal( BcPIDIV4, (BcReal)pClient->getWidth() / (BcReal)pClient->getHeight(), 1.0f, 1024.0f ); WorldView_.lookAt( BcVec3d( 0.0f, 350.0f, 270.0f ), BcVec3d( 0.0f, 0.0f, 0.0f ), BcVec3d( 0.0f, 0.0f, 1.0f ) ); if( SsCore::pImpl() != NULL ) { SsCore::pImpl()->setListener( BcVec3d( 0.0f, 350.0f, 270.0f ), BcVec3d( 0.0f, -4.0f, -2.0f ).normal(), BcVec3d( 0.0f, 0.0f, 1.0f ) ); } setMaterialComponentParams( BackgroundMaterialComponent_, BcMat4d() ); Canvas_->setMaterialComponent( BackgroundMaterialComponent_ ); Canvas_->drawSpriteCentered3D( BcVec3d( 0.0f, 0.0f, 0.0f ), WorldHalfSize_ * 4.0f, 0, RsColour::WHITE, 0 ); // Render entities. for( BcU32 Idx = 0; Idx < Entities_.size(); ++Idx ) { GaGameComponent* pEntity = Entities_[ Idx ]; pEntity->render( Canvas_ ); } // Draw foreground. BcMat4d Ortho; Ortho.orthoProjection( -WorldHalfSize_.x(), WorldHalfSize_.x(), -WorldHalfSize_.y(), WorldHalfSize_.y(), -1.0f, 0.0f ); Canvas_->pushMatrix( Ortho ); Canvas_->setMaterialComponent( ForegroundMaterialComponent_ ); Canvas_->drawSpriteCentered( BcVec2d( 0.0f, 0.0f ), BcVec2d( WorldHalfSize_.x() * 2.2f, WorldHalfSize_.y() * -2.0f ), 0, RsColour::WHITE, 20 ); BcReal Width = BcMax( 0.0f, FoodHealth_ - 0.5f ) * 2.0f; RsColour Colour; Colour.lerp( RsColour::RED, RsColour::GREEN, Width ); Canvas_->setMaterialComponent( BarMaterialComponent_ ); Canvas_->drawSpriteCentered( BcVec2d( 0.0f, WorldHalfSize_.y() - ( WorldHalfSize_.y() * 0.05f ) ), BcVec2d( WorldHalfSize_.x() * 1.5f * Width, WorldHalfSize_.y() * 0.05f ), 0, Colour, 20 ); Canvas_->popMatrix(); // Base render. GaBaseGameState::render(); }
////////////////////////////////////////////////////////////////////////// // makeAbsoluteTransform void MdlNode::makeAbsoluteTransform( const BcMat4d& ParentAbsolute ) { // Parent another node to this tree. MdlNode* pNextNode = pChild_; // BcMat4d InverseParent = ParentAbsolute; InverseParent.inverse(); AbsoluteTransform_ = ParentAbsolute * RelativeTransform_; // For all the nodes parented to the same as us. while( pNextNode != NULL ) { pNextNode->makeAbsoluteTransform( AbsoluteTransform_ ); pNextNode = pNextNode->pNext_; } }
//virtual void ScnParticleSystemComponent::render( RsFrame* pFrame, RsRenderSort Sort ) { // 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 BcVec2d HalfSize = Particle.Scale_ * 0.5f; // Crappy rotation implementation :P const BcReal Radians = Particle.CurrentTime_ * Particle.RotationMultiplier_; BcVec2d CornerA = BcVec2d( -1.0f, -1.0f ) * HalfSize; BcVec2d CornerB = BcVec2d( 1.0f, -1.0f ) * HalfSize; BcVec2d CornerC = BcVec2d( 1.0f, 1.0f ) * HalfSize; BcVec2d CornerD = BcVec2d( -1.0f, 1.0f ) * HalfSize; if( Radians != NULL ) { BcMat4d Rotation; Rotation.rotation( BcVec3d( 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_ = Particle.UVBounds_.x(); VertexA.V_ = Particle.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_ = Particle.UVBounds_.z(); VertexB.V_ = Particle.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_ = Particle.UVBounds_.z(); VertexC.V_ = Particle.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_ = Particle.UVBounds_.z(); VertexD.V_ = Particle.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_ = Particle.UVBounds_.x(); VertexE.V_ = Particle.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_ = Particle.UVBounds_.x(); VertexF.V_ = Particle.UVBounds_.y(); VertexF.RGBA_ = Colour; // ++NoofParticlesToRender; } } // Update and unlock vertex buffer. VertexBuffer.pVertexBuffer_->setNoofUpdateVertices( NoofParticlesToRender * 6 ); VertexBuffer.pVertexBuffer_->unlock(); // Bind material. MaterialComponent_->setParameter( WorldTransformParam_, BcMat4d() ); 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 ); }
////////////////////////////////////////////////////////////////////////// // GaGameComponent //virtual void GaGameComponent::update( BcReal Tick ) { BcU32 Param = FontMaterial_->findParameter( "aAlphaTestStep" ); FontMaterial_->setParameter( Param, BcVec2d( 0.4f, 0.5f ) ); if( GameState_ == GS_PLAYING ) { pSimulator_->tick( Tick ); if( pSimulator_->getTimeOut() > 5.0f ) { GameState_ = GS_TIMEOUT; } if( pSimulator_->getUnitCount( TeamID_ ) == 0 || pSimulator_->getUnitCount( 1 - TeamID_ ) == 0 ) { GameState_ = GS_OVER; } if( !Networked_ ) { AITickTime_ -= Tick; if( AITickTime_ < 0.0f ) { pSimulator_->runAI( 1 - TeamID_ ); AITickTime_ = AITickMaxTime_; } } } //if( TeamID_ == 0 ) { if( CanvasComponent_.isValid() ) { OsClient* pClient = OsCore::pImpl()->getClient( 0 ); BcReal HW = static_cast< BcReal >( pClient->getWidth() ) / 2.0f; BcReal HH = static_cast< BcReal >( pClient->getHeight() ) / 2.0f; BcReal AspectRatio = HW / HH; BcMat4d Ortho; Ortho.orthoProjection( -HW, HW, HH, -HH, -1.0f, 1.0f ); // Clear canvas and push projection matrix. CanvasComponent_->clear(); CanvasComponent_->pushMatrix( Ortho ); CanvasComponent_->setMaterialComponent( BackgroundMaterial_ ); CanvasComponent_->drawSpriteCentered( BcVec2d( 0.0f, 0.0f ), BcVec2d( 1280.0f, 720.0f ), 0, RsColour( 1.0f, 1.0f, 1.0f, 1.0f ), 0 ); CanvasComponent_->setMaterialComponent( SpriteSheetMaterials_[ 0 ] ); pSimulator_->render( CanvasComponent_, 0 ); CanvasComponent_->setMaterialComponent( SpriteSheetMaterials_[ 1 ] ); pSimulator_->render( CanvasComponent_, 1 ); // Find unit over mouse. GaGameUnitIDList SelectionList; if( MouseDown_ ) { if( BoxSelection_ ) { pSimulator_->findUnits( SelectionList, StartGameCursorPosition_, EndGameCursorPosition_, BcErrorCode, BcErrorCode ); } } else { pSimulator_->findUnits( SelectionList, GameCursorPosition_, 0.8f, BcErrorCode, BcErrorCode ); while( SelectionList.size() > 1 ) { SelectionList.pop_back(); } } for( BcU32 Idx = 0; Idx < UnitSelection_.size(); ++Idx ) { SelectionList.push_back( UnitSelection_[ Idx ] ); } CanvasComponent_->setMaterialComponent( HUDMaterial_ ); pSimulator_->renderHUD( CanvasComponent_, SelectionList, TeamID_ ); } switch( GameState_ ) { case GS_PLAYING: { // Draw cursor. CanvasComponent_->setMaterialComponent( HUDMaterial_ ); CanvasComponent_->drawSpriteCentered( BcVec2d( CursorPosition_.x(), CursorPosition_.y() ), BcVec2d( 64.0f, 64.0f ), 1, AttackMove_ ? RsColour::RED : RsColour::WHITE, 10 ); // Draw selection box. if( MouseDown_ && BoxSelection_ ) { BcVec2d Min = BcVec2d( StartGameCursorPosition_.x(), StartGameCursorPosition_.y() ) * 32.0f; BcVec2d Max = BcVec2d( GameCursorPosition_.x(), GameCursorPosition_.y() ) * 32.0f; CanvasComponent_->drawSprite( Min, Max - Min, 0, RsColour::GREEN * RsColour( 1.0f, 1.0f, 1.0f, 0.1f ), 11 ); } std::string Text0 = TeamID_ == 0 ? "YOU ARE RED!" : "YOU ARE BLUE!"; BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -350.0f ), Text0, TeamID_ == 0 ? RsColour::RED : RsColour::BLUE, BcFalse ); } break; case GS_TIMEOUT: { std::string Text0 = "Connection timed out :("; std::string Text1 = "Press ESC to Quit."; BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse ); BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse ); } break; case GS_OVER: { if( pSimulator_->getUnitCount( TeamID_ ) > 0 ) { std::string Text0 = "You Won! :D"; std::string Text1 = "Press ESC to Quit."; BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse ); BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse ); } else { std::string Text0 = "You Lost! :<"; std::string Text1 = "Press ESC to Quit."; BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse ); BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue ); Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse ); } } break; } } }
////////////////////////////////////////////////////////////////////////// // load MdlNode* MD5MeshLoader::load( const BcChar* FileName, const BcChar* NodeName ) { BcFile File; BcBool Ret; ParseMode_ = PM_MAIN; BcU32 iJoint = 0; BcU32 iMesh = 0; BcU32 iVert = 0; BcU32 iInd = 0; BcU32 iWeight = 0; if( File.open( FileName ) == BcFalse ) { return NULL; } BcChar Buffer[1024]; BcChar Command[1024]; BcChar* pBuffer; // Begin the parsage. while( !File.eof() ) { // Parse a line without the spaces at the start or tabs. { pBuffer = &Buffer[0]; BcChar TheChar = 0; BcBool bAtSentence = BcFalse; while( TheChar != 10 && !File.eof() ) { File.read( &TheChar, 1 ); if ( TheChar != '\t' ) { bAtSentence = BcTrue; } if ( TheChar != 10 && TheChar != 13 && bAtSentence ) { *pBuffer = TheChar; ++pBuffer; Ret = ( pBuffer < ( Buffer + 1024 ) ); BcAssert( Ret ); if( !Ret ) { return NULL; } } } // Terminate it. *pBuffer = 0; ++pBuffer; } sscanf( Buffer, "%s", Command ); if ( BcStrLength( Buffer ) == 0 ) { Command[ 0 ] = 0; } switch( ParseMode_ ) { case PM_MAIN: { if( BcStrCompare( "numJoints", Command ) ) { sscanf( Buffer, "numJoints %u", &nJoints_ ); pJoints_ = new MD5_Joint[ nJoints_ ]; } else if( BcStrCompare( "numMeshes", Command ) ) { sscanf( Buffer, "numMeshes %u", &nMeshes_ ); pMeshes_ = new MD5_Mesh[ nMeshes_ ]; } else if( BcStrCompare( "joints", Command ) ) { ParseMode_ = PM_JOINTS; } else if( BcStrCompare( "mesh", Command ) ) { ParseMode_ = PM_MESH; iVert = 0; iInd = 0; iWeight = 0; } } break; case PM_JOINTS: { if( BcStrCompare( "}", Command ) ) { ParseMode_ = PM_MAIN; } else { // Parse a joint off. BcAssert( iJoint < nJoints_ ); MD5_Joint* pJoint = &pJoints_[ iJoint ]; sscanf( Buffer, "%s %i ( %f %f %f ) ( %f %f %f )", pJoint->Name_, &pJoint->ParentID_, &pJoint->TX_, &pJoint->TY_, &pJoint->TZ_, &pJoint->QX_, &pJoint->QY_, &pJoint->QZ_ ); ++iJoint; } } break; case PM_MESH: { if( BcStrCompare( "}", Command ) ) { ++iMesh; ParseMode_ = PM_MAIN; } else { BcAssert( iMesh < nMeshes_ ); MD5_Mesh* pMesh = &pMeshes_[ iMesh ]; if ( BcStrCompare( "shader", Command ) ) { sscanf( Buffer, "shader \"%s", pMesh->Shader_ ); BcU32 i = BcStrLength( pMesh->Shader_ ) - 1; pMesh->Shader_[ i ] = '\0'; } else if ( BcStrCompare( "numverts", Command ) ) { sscanf( Buffer, "numverts %u", &pMesh->nVerts_ ); pMesh->pVerts_ = new MD5_Vert[ pMesh->nVerts_ ]; } else if ( BcStrCompare( "vert", Command ) ) { // Parse a vert off BcAssert( iVert < pMesh->nVerts_ ); MD5_Vert* pVert = &pMesh->pVerts_[ iVert ]; sscanf( Buffer, "vert %i ( %f %f ) %i %i", &pVert->Index_, &pVert->U_, &pVert->V_, &pVert->WeightIndex_, &pVert->nWeights_ ); ++iVert; } else if ( BcStrCompare( "numtris", Command ) ) { sscanf( Buffer, "numtris %u", &pMesh->nIndices_ ); pMesh->nIndices_ *= 3; pMesh->pIndices_ = new BcU32[ pMesh->nIndices_ ]; } else if ( BcStrCompare( "tri", Command ) ) { // Parse a vert off BcAssert( iInd < pMesh->nIndices_ ); BcU32 Index; BcU32* pIndex = &pMesh->pIndices_[ iInd ]; sscanf( Buffer, "tri %i %i %i %i", &Index, &pIndex[0], &pIndex[1], &pIndex[2] ); iInd += 3; } else if ( BcStrCompare( "numweights", Command ) ) { sscanf( Buffer, "numweights %u", &pMesh->nWeights_ ); pMesh->pWeights_ = new MD5_Weight[ pMesh->nWeights_ ]; } else if ( BcStrCompare( "weight", Command ) ) { // Parse a vert off BcAssert( iWeight < pMesh->nWeights_ ); MD5_Weight* pWeight = &pMesh->pWeights_[ iWeight ]; sscanf( Buffer, "weight %i %i %f ( %f %f %f )", &pWeight->Index_, &pWeight->JointID_, &pWeight->Weight_, &pWeight->X_, &pWeight->Y_, &pWeight->Z_ ); ++iWeight; } } } break; } } // Now that we are loaded we can build the node graph. MdlNode* pRootNode = new MdlNode(); pRootNode->name( NodeName ); for( BcU32 i = 0; i < nMeshes_; ++i ) { buildBindPose( pRootNode, i ); } // Parent joints up. //if( nJoints_ > 1 ) { for( BcU32 i = 0; i < nJoints_; ++i ) { MD5_Joint* pJoint = &pJoints_[ i ]; MdlNode* pNode = new MdlNode(); pNode->name( pJoint->Name_ ); pNode->type( eNT_JOINT ); // Build the transform and inverse bind pose. BcQuat JointRot( pJoint->QX_, pJoint->QY_, pJoint->QZ_, 0.0f ); JointRot.calcFromXYZ(); BcMat4d JointRotation; BcMat4d JointTranslate; BcMat4d JointTransform; BcMat4d InverseBindpose; JointRot.asMatrix4d( JointRotation ); JointTranslate.identity(); JointTranslate.row3( BcVec4d( pJoint->TX_, pJoint->TY_, pJoint->TZ_, 1.0f ) ); JointTransform = JointRotation * JointTranslate; InverseBindpose = JointTransform; InverseBindpose.inverse(); pNode->absoluteTransform( JointTransform ); pNode->inverseBindpose( InverseBindpose ); if( pJoint->ParentID_ != BcErrorCode ) { pRootNode->parentNode( pNode, pJoints_[ pJoint->ParentID_ ].Name_ ); } else { // Parent to root. pRootNode->parentNode( pNode, pRootNode->name() ); } } } // Cleanup nJoints_ = 0; delete [] pJoints_; pJoints_ = NULL; for( BcU32 i = 0; i < nMeshes_; ++i ) { delete [] pMeshes_[ i ].pIndices_; delete [] pMeshes_[ i ].pVerts_; delete [] pMeshes_[ i ].pWeights_; } nMeshes_ = 0; delete [] pMeshes_; pMeshes_ = NULL; // BcMat4d RootTransform; RootTransform.identity(); pRootNode->makeRelativeTransform( RootTransform ); return pRootNode; }