#include "core/Background2D.h" #include #include #include #include #include "core/CameraManager.h" #include "core/ConfigVar.h" #include "core/DebugDraw.h" #include "core/Logger.h" #include "core/Timer.h" //------------------------------------------------------------------------------ ConfigVar cv_debug_background2d( "debug_background2d", "Draw background debug info", "false" ); ConfigVar cv_show_background2d( "show_background2d", "Draw background", "true" ); ConfigVar cv_background2d_manual( "background2d_manual", "Manual scrolling for 2d background", "false" ); //------------------------------------------------------------------------------ Background2D::Background2D(): m_AlphaMaxVertexCount( 0 ), m_AddMaxVertexCount( 0 ), m_SubtractMaxVertexCount( 0 ), m_MultiplyMaxVertexCount( 0 ), m_ScrollEntity( NULL ), m_ScrollPositionStart( Ogre::Vector2::ZERO ), m_ScrollPositionEnd( Ogre::Vector2::ZERO ), m_ScrollType( Background2D::NONE ), m_ScrollSeconds( 0 ), m_ScrollCurrentSeconds( 0 ), m_Position( Ogre::Vector2::ZERO ), m_PositionReal( Ogre::Vector2::ZERO ) ,m_range( Ogre::AxisAlignedBox::BOX_INFINITE ) // for ffvii ,m_virtual_screen_size( 320, 240 ) { m_SceneManager = Ogre::Root::getSingleton().getSceneManager( "Scene" ); m_RenderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem(); CreateVertexBuffers(); m_AlphaMaterial = Ogre::MaterialManager::getSingleton().create( "Background2DAlpha", "General" ); Ogre::Pass* pass = m_AlphaMaterial->getTechnique( 0 )->getPass( 0 ); pass->setVertexColourTracking( Ogre::TVC_AMBIENT ); pass->setCullingMode( Ogre::CULL_NONE ); pass->setDepthCheckEnabled( true ); pass->setDepthWriteEnabled( true ); pass->setLightingEnabled( false ); pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); pass->setAlphaRejectFunction( Ogre::CMPF_GREATER ); pass->setAlphaRejectValue( 0 ); Ogre::TextureUnitState* tex = pass->createTextureUnitState(); tex->setTextureName( "system/blank.png" ); tex->setNumMipmaps( -1 ); tex->setTextureFiltering( Ogre::TFO_NONE ); m_AddMaterial = Ogre::MaterialManager::getSingleton().create( "Background2DAdd", "General" ); pass = m_AddMaterial->getTechnique( 0 )->getPass( 0 ); pass->setVertexColourTracking( Ogre::TVC_AMBIENT ); pass->setCullingMode( Ogre::CULL_NONE ); pass->setDepthCheckEnabled( true ); pass->setDepthWriteEnabled( true ); pass->setLightingEnabled( false ); pass->setSceneBlending( Ogre::SBT_ADD ); pass->setAlphaRejectFunction( Ogre::CMPF_GREATER ); pass->setAlphaRejectValue( 0 ); tex = pass->createTextureUnitState(); tex->setTextureName( "system/blank.png" ); tex->setNumMipmaps( -1 ); tex->setTextureFiltering( Ogre::TFO_NONE ); m_SubtractMaterial = Ogre::MaterialManager::getSingleton().create( "Background2DSubtract", "General" ); pass = m_SubtractMaterial->getTechnique( 0 )->getPass( 0 ); pass->setVertexColourTracking( Ogre::TVC_AMBIENT ); pass->setCullingMode( Ogre::CULL_NONE ); pass->setDepthCheckEnabled( true ); pass->setDepthWriteEnabled( true ); pass->setLightingEnabled( false ); pass->setSceneBlending( Ogre::SBF_ONE, Ogre::SBF_ONE_MINUS_SOURCE_COLOUR ); // FIXME: SUBTRACT pass->setAlphaRejectFunction( Ogre::CMPF_LESS ); pass->setAlphaRejectValue( 0 ); tex = pass->createTextureUnitState(); tex->setTextureName( "system/blank.png" ); tex->setNumMipmaps( -1 ); tex->setTextureFiltering( Ogre::TFO_NONE ); m_MultiplyMaterial = Ogre::MaterialManager::getSingleton().create( "Background2DMultiply", "General" ); pass = m_MultiplyMaterial->getTechnique( 0 )->getPass( 0 ); pass->setVertexColourTracking( Ogre::TVC_AMBIENT ); pass->setCullingMode( Ogre::CULL_NONE ); pass->setDepthCheckEnabled( true ); pass->setDepthWriteEnabled( true ); pass->setLightingEnabled( false ); pass->setSceneBlending( Ogre::SBT_ADD ); // FIXME: MULTIPLY pass->setAlphaRejectFunction( Ogre::CMPF_GREATER ); pass->setAlphaRejectValue( 0 ); tex = pass->createTextureUnitState(); tex->setTextureName( "system/blank.png" ); tex->setNumMipmaps( -1 ); tex->setTextureFiltering( Ogre::TFO_NONE ); m_SceneManager->addRenderQueueListener( this ); } //------------------------------------------------------------------------------ Background2D::~Background2D() { m_SceneManager->removeRenderQueueListener( this ); for( unsigned int i = 0; i < m_Animations.size(); ++i ) { delete m_Animations[ i ]; } DestroyVertexBuffers(); } //------------------------------------------------------------------------------ void Background2D::InputDebug(const QGears::Event& event) { if( cv_background2d_manual.GetB() == true ) { if (event.type == QGears::ET_KEY_IMPULSE && event.param1 == OIS::KC_W) { m_PositionReal.y += 2; } else if (event.type == QGears::ET_KEY_IMPULSE && event.param1 == OIS::KC_A) { m_PositionReal.x += 2; } else if (event.type == QGears::ET_KEY_IMPULSE && event.param1 == OIS::KC_S) { m_PositionReal.y -= 2; } else if (event.type == QGears::ET_KEY_IMPULSE && event.param1 == OIS::KC_D) { m_PositionReal.x -= 2; } CameraManager::getSingleton().Set2DScroll( m_PositionReal ); } } //------------------------------------------------------------------------------ void Background2D::Update() { for( unsigned int i = 0; i < m_AnimationPlayed.size(); ++i ) { for( unsigned int j = 0; j < m_Animations.size(); ++j ) { if( m_Animations[ j ]->GetName() == m_AnimationPlayed[ i ].name ) { float delta_time = Timer::getSingleton().GetGameTimeDelta(); float time = m_Animations[ j ]->GetTime(); float end_time = m_Animations[ j ]->GetLength(); // if animation ended if( time + delta_time >= end_time ) { // set to last frame of animation if( time != end_time ) { m_Animations[ j ]->SetTime( end_time ); } if( m_AnimationPlayed[ i ].state == Background2DAnimation::ONCE ) { for( unsigned int k = 0; k < m_AnimationPlayed[ i ].sync.size(); ++k ) { ScriptManager::getSingleton().ContinueScriptExecution( m_AnimationPlayed[ i ].sync[ k ] ); } m_AnimationPlayed[ i ].sync.clear(); m_AnimationPlayed[ i ].name = ""; // mark to erase this way } else // LOOPED { // in case of looped we need to sync with end m_Animations[ j ]->SetTime( time + delta_time - end_time ); } } else { m_Animations[ j ]->AddTime( delta_time ); } } } } // remove stopped animations std::vector< AnimationPlayed >::iterator i = m_AnimationPlayed.begin(); for( ; i != m_AnimationPlayed.end(); ) { if( ( *i ).name == "" ) { i = m_AnimationPlayed.erase( i ); } else { ++i; } } } //------------------------------------------------------------------------------ void Background2D::UpdateDebug() { // is this necessary? does it cost to apply camera 2d Scroll? // if so maybe move this check to applyScroll if( m_PositionReal != GetScreenScroll() ) { applyScroll(); } if( cv_debug_background2d.GetB() == true ) { DEBUG_DRAW.SetTextAlignment( DEBUG_DRAW.LEFT ); DEBUG_DRAW.SetScreenSpace( true ); DEBUG_DRAW.SetColour( Ogre::ColourValue( 0.0f, 0.8f, 0.8f, 1.0f ) ); for( unsigned int i = 0; i < m_AnimationPlayed.size(); ++i ) { DEBUG_DRAW.Text( 150.0f, static_cast(34 + i * 12), "Background 2D animation: " + m_AnimationPlayed[ i ].name ); } } } //------------------------------------------------------------------------------ void Background2D::calculateScreenScale( void ) { Ogre::Viewport *viewport( CameraManager::getSingleton().getViewport() ); Ogre::Real scale_width = static_cast(viewport->getActualWidth()); Ogre::Real scale_height = static_cast(viewport->getActualHeight()); scale_width /= m_virtual_screen_size.x; scale_height /= m_virtual_screen_size.y; m_screen_scale = scale_height; m_screen_proportion.x = m_screen_scale / scale_width; m_screen_proportion.y = m_screen_scale / scale_height; } //------------------------------------------------------------------------------ void Background2D::OnResize() { calculateScreenScale(); for( unsigned int i = 0; i < m_Tiles.size(); ++i ) { Tile &tile( m_Tiles[ i ] ); Ogre::Vector2 top_left(static_cast(tile.x), static_cast(- tile.y)); Ogre::Vector2 top_right(static_cast(tile.x + tile.width), static_cast(top_left.y)); Ogre::Vector2 bottom_right(static_cast(top_right.x), static_cast(-(tile.y + tile.height))); Ogre::Vector2 bottom_left(static_cast(top_left.x), static_cast(bottom_right.y)); virtualScreenToWorldSpace( top_left ); virtualScreenToWorldSpace( top_right ); virtualScreenToWorldSpace( bottom_right ); virtualScreenToWorldSpace( bottom_left ); float new_x1 = top_left.x; float new_y1 = top_left.y; float new_x2 = top_right.x; float new_y2 = top_right.y; float new_x3 = bottom_right.x; float new_y3 = bottom_right.y; float new_x4 = bottom_left.x; float new_y4 = bottom_left.y; Ogre::HardwareVertexBufferSharedPtr vertex_buffer; if( m_Tiles[ i ].blending == QGears::B_ALPHA ) { vertex_buffer = m_AlphaVertexBuffer; } else if( m_Tiles[ i ].blending == QGears::B_ADD ) { vertex_buffer = m_AddVertexBuffer; } else if( m_Tiles[ i ].blending == QGears::B_SUBTRACT ) { vertex_buffer = m_SubtractVertexBuffer; } else if( m_Tiles[ i ].blending == QGears::B_MULTIPLY ) { vertex_buffer = m_MultiplyVertexBuffer; } float* writeIterator = ( float* )vertex_buffer->lock( Ogre::HardwareBuffer::HBL_NORMAL ); writeIterator += m_Tiles[ i ].start_vertex_index * TILE_VERTEX_INDEX_SIZE; *writeIterator++ = new_x1; *writeIterator++ = new_y1; writeIterator += 7; *writeIterator++ = new_x2; *writeIterator++ = new_y2; writeIterator += 7; *writeIterator++ = new_x3; *writeIterator++ = new_y3; writeIterator += 7; ///* *writeIterator++ = new_x1; *writeIterator++ = new_y1; writeIterator += 7; *writeIterator++ = new_x3; *writeIterator++ = new_y3; writeIterator += 7; //*/ *writeIterator++ = new_x4; *writeIterator++ = new_y4; vertex_buffer->unlock(); } applyScroll(); } //------------------------------------------------------------------------------ void Background2D::Clear() { m_ScrollEntity = NULL; m_ScrollPositionStart = Ogre::Vector2::ZERO; m_ScrollPositionEnd = Ogre::Vector2::ZERO; m_ScrollSeconds = 0; m_ScrollCurrentSeconds = 0; m_Position = Ogre::Vector2::ZERO; m_PositionReal = Ogre::Vector2::ZERO; m_range = Ogre::AxisAlignedBox::BOX_INFINITE; UnsetScroll(); for( unsigned int i = 0; i < m_Animations.size(); ++i ) { delete m_Animations[ i ]; } m_Animations.clear(); for( unsigned int i = 0; i < m_AnimationPlayed.size(); ++i ) { for( unsigned int j = 0; j < m_AnimationPlayed[ i ].sync.size(); ++j ) { ScriptManager::getSingleton().ContinueScriptExecution( m_AnimationPlayed[ i ].sync[ j ] ); } } m_AnimationPlayed.clear(); m_Tiles.clear(); DestroyVertexBuffers(); CreateVertexBuffers(); } //------------------------------------------------------------------------------ void Background2D::ScriptAutoScrollToEntity( Entity* entity ) { m_ScrollEntity = entity; } //------------------------------------------------------------------------------ Entity* Background2D::GetAutoScrollEntity() const { return m_ScrollEntity; } //------------------------------------------------------------------------------ void Background2D::ScriptScrollToPosition( const float x, const float y, const ScrollType type, const float seconds ) { LOG_TRIVIAL( "[SCRIPT] Background2d set scroll to position \"" + Ogre::StringConverter::toString( Ogre::Vector2( x, y ) ) + "\"." ); Ogre::Vector2 position = Ogre::Vector2( x, y ); m_ScrollEntity = NULL; if( type == Background2D::NONE ) { SetScroll( position ); return; } m_ScrollPositionStart = m_Position; m_ScrollPositionEnd = position; m_ScrollType = type; m_ScrollSeconds = seconds; m_ScrollCurrentSeconds = 0; } //------------------------------------------------------------------------------ int Background2D::ScriptScrollSync() { ScriptId script = ScriptManager::getSingleton().GetCurrentScriptId(); LOG_TRIVIAL( "[SCRIPT] Wait Background2d scroll for function \"" + script.function + "\" in script entity \"" + script.entity + "\"." ); m_ScrollSync.push_back( script ); return -1; } //------------------------------------------------------------------------------ void Background2D::UnsetScroll() { m_ScrollType = Background2D::NONE; for( unsigned int i = 0; i < m_ScrollSync.size(); ++i ) { ScriptManager::getSingleton().ContinueScriptExecution( m_ScrollSync[ i ] ); } m_ScrollSync.clear(); } //------------------------------------------------------------------------------ const Ogre::Vector2& Background2D::GetScrollPositionStart() const { return m_ScrollPositionStart; } //------------------------------------------------------------------------------ const Ogre::Vector2& Background2D::GetScrollPositionEnd() const { return m_ScrollPositionEnd; } //------------------------------------------------------------------------------ Background2D::ScrollType Background2D::GetScrollType() const { return m_ScrollType; } //------------------------------------------------------------------------------ float Background2D::GetScrollSeconds() const { return m_ScrollSeconds; } //------------------------------------------------------------------------------ void Background2D::SetScrollCurrentSeconds( const float seconds ) { m_ScrollCurrentSeconds = seconds; } //------------------------------------------------------------------------------ float Background2D::GetScrollCurrentSeconds() const { return m_ScrollCurrentSeconds; } //------------------------------------------------------------------------------ void Background2D::SetScreenScroll( const Ogre::Vector2& position ) { SetScroll( position / m_screen_scale ); } //------------------------------------------------------------------------------ void Background2D::SetScroll( const Ogre::Vector2& position ) { m_Position = position; Ogre::Vector3 pos_3d( m_Position.x, m_Position.y, 0 ); if( !m_range.contains( pos_3d ) ) { Ogre::Vector3 max_3d( m_range.getMaximum() ); Ogre::Vector3 min_3d( m_range.getMinimum() ); Ogre::Vector2 max( max_3d.x, max_3d.y ); Ogre::Vector2 min( min_3d.x, min_3d.y ); m_Position.makeCeil( min ); m_Position.makeFloor( max ); } applyScroll(); } //------------------------------------------------------------------------------ void Background2D::applyScroll() { if( cv_background2d_manual.GetB() != true ) { m_PositionReal = GetScreenScroll(); CameraManager::getSingleton().Set2DScroll( m_PositionReal ); } } //------------------------------------------------------------------------------ const Ogre::Vector2& Background2D::GetScroll() const { return m_Position; } //------------------------------------------------------------------------------ const Ogre::Vector2 Background2D::GetScreenScroll() const { return GetScroll() * m_screen_scale; } //------------------------------------------------------------------------------ void Background2D::SetImage( const Ogre::String& image ) { Ogre::LogManager::getSingleton().stream() << "Background2D::SetImage " << image; Ogre::Pass* pass = m_AlphaMaterial->getTechnique( 0 )->getPass( 0 ); Ogre::TextureUnitState* tex = pass->getTextureUnitState( 0 ); tex->setTextureName( image ); pass = m_AddMaterial->getTechnique( 0 )->getPass( 0 ); tex = pass->getTextureUnitState( 0 ); tex->setTextureName( image ); pass = m_SubtractMaterial->getTechnique( 0 )->getPass( 0 ); tex = pass->getTextureUnitState( 0 ); tex->setTextureName( image ); pass = m_MultiplyMaterial->getTechnique( 0 )->getPass( 0 ); tex = pass->getTextureUnitState( 0 ); tex->setTextureName( image ); } //------------------------------------------------------------------------------ void Background2D::SetRange( const Ogre::Vector4& range ) { SetRange( ( int )range.x, ( int )range.y, ( int )range.z, ( int )range.w ); } //------------------------------------------------------------------------------ void Background2D::SetRange( const int min_x, const int min_y, const int max_x, const int max_y ) { Ogre::LogManager::getSingleton().stream() << "Background2D::SetRange " << min_x << " " << min_y << " " << max_x << " " << max_y; Ogre::Vector2 half_virtual_screen_size( m_virtual_screen_size / 2 ); half_virtual_screen_size /= m_screen_proportion; m_range.setMaximum( max_x - half_virtual_screen_size.x , max_y - half_virtual_screen_size.y, 1 ); m_range.setMinimum( min_x + half_virtual_screen_size.x , min_y + half_virtual_screen_size.y, 0 ); Ogre::LogManager::getSingleton().stream() << "Background2D::SetRange " << m_range; calculateScreenScale(); } //------------------------------------------------------------------------------ void Background2D::AddTile( const QGears::Tile& tile ) { // TODO: move depth calculation to flevelBackgroundLoader maybe? and let Backgorund2D only handle 0 <= depth <= 1 or so? // maybe just move the < 4095 part to flevel background loader? Ogre::Real depth( 0.0001f ); if( tile.depth >= 1 ) { if( tile.depth < 4095 ) { const Ogre::Matrix4 &cam_projection( CameraManager::getSingleton().GetCurrentCamera()->getProjectionMatrixWithRSDepth() ); Ogre::Vector4 res( 0, 0, -tile.depth, 1 ); res = cam_projection * res; res /= res.w; depth = res.z; } else { depth = 0.9999f; } } AddTile( tile.destination, tile.width, tile.height, depth, tile.uv, tile.blending ); } //------------------------------------------------------------------------------ void Background2D::AddTile( const Ogre::Vector2& destination, const int width, const int height, const float depth, const Ogre::Vector4& uv, const Blending blending ) { AddTile( static_cast(destination.x), static_cast(destination.y), width, height, depth, uv.x, uv.y, uv.z, uv.w, blending ); } //------------------------------------------------------------------------------ void Background2D::virtualScreenToWorldSpace( Ogre::Vector2& pos ) const { pos.x /= m_virtual_screen_size.x / 2; pos.y /= m_virtual_screen_size.y / 2; pos.x *= m_screen_proportion.x; pos.y *= m_screen_proportion.y; } //------------------------------------------------------------------------------ void Background2D::AddTile( const int x, const int y, const int width, const int height, const float depth, const float u1, const float v1, const float u2, const float v2, const Blending blending ) { Ogre::RenderOperation render_op; Ogre::HardwareVertexBufferSharedPtr vertex_buffer; unsigned int max_vertex_count; if( blending == QGears::B_ALPHA ) { render_op = m_AlphaRenderOp; vertex_buffer = m_AlphaVertexBuffer; max_vertex_count = m_AlphaMaxVertexCount; } else if( blending == QGears::B_ADD ) { render_op = m_AddRenderOp; vertex_buffer = m_AddVertexBuffer; max_vertex_count = m_AddMaxVertexCount; } else if( blending == QGears::B_SUBTRACT ) { render_op = m_SubtractRenderOp; vertex_buffer = m_SubtractVertexBuffer; max_vertex_count = m_SubtractMaxVertexCount; } else if( blending == QGears::B_MULTIPLY ) { render_op = m_MultiplyRenderOp; vertex_buffer = m_MultiplyVertexBuffer; max_vertex_count = m_MultiplyMaxVertexCount; } else { LOG_ERROR( "Unknown blending type." ); return; } if( render_op.vertexData->vertexCount + TILE_VERTEX_COUNT > max_vertex_count ) { LOG_ERROR( "Max number of tiles reached. Can't create more than " + Ogre::StringConverter::toString( max_vertex_count / TILE_VERTEX_COUNT ) + " tiles." ); return; } Tile tile; tile.x = x; tile.y = y; tile.width = width; tile.height = height; tile.start_vertex_index = render_op.vertexData->vertexCount; tile.blending = blending; size_t index( m_Tiles.size() ); m_Tiles.push_back( tile ); Ogre::Vector2 top_left(static_cast(x), static_cast(-y)); Ogre::Vector2 top_right(static_cast(x + width), static_cast(top_left.y)); Ogre::Vector2 bottom_right(static_cast(top_right.x), static_cast(-(y + height))); Ogre::Vector2 bottom_left( top_left.x, bottom_right.y ); virtualScreenToWorldSpace( top_left ); virtualScreenToWorldSpace( top_right ); virtualScreenToWorldSpace( bottom_right ); virtualScreenToWorldSpace( bottom_left ); float new_x1 = top_left.x; float new_y1 = top_left.y; float new_x2 = top_right.x; float new_y2 = top_right.y; float new_x3 = bottom_right.x; float new_y3 = bottom_right.y; float new_x4 = bottom_left.x; float new_y4 = bottom_left.y; float* writeIterator = ( float* )vertex_buffer->lock( Ogre::HardwareBuffer::HBL_NORMAL ); writeIterator += render_op.vertexData->vertexCount * TILE_VERTEX_INDEX_SIZE; *writeIterator++ = new_x1; *writeIterator++ = new_y1; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u1; *writeIterator++ = v1; *writeIterator++ = new_x2; *writeIterator++ = new_y2; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u2; *writeIterator++ = v1; *writeIterator++ = new_x3; *writeIterator++ = new_y3; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u2; *writeIterator++ = v2; *writeIterator++ = new_x1; *writeIterator++ = new_y1; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u1; *writeIterator++ = v1; *writeIterator++ = new_x3; *writeIterator++ = new_y3; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u2; *writeIterator++ = v2; *writeIterator++ = new_x4; *writeIterator++ = new_y4; *writeIterator++ = depth; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = 1; *writeIterator++ = u1; *writeIterator++ = v2; render_op.vertexData->vertexCount += TILE_VERTEX_COUNT; vertex_buffer->unlock(); } //------------------------------------------------------------------------------ void Background2D::UpdateTileUV( const unsigned int tile_id, const float u1, const float v1, const float u2, const float v2 ) { if( tile_id >= m_Tiles.size() ) { LOG_ERROR( "Tile with id " + Ogre::StringConverter::toString( tile_id ) + " doesn't exist." ); return; } Ogre::HardwareVertexBufferSharedPtr vertex_buffer; if( m_Tiles[ tile_id ].blending == QGears::B_ALPHA ) { vertex_buffer = m_AlphaVertexBuffer; } else if( m_Tiles[ tile_id ].blending == QGears::B_ADD ) { vertex_buffer = m_AddVertexBuffer; } else if( m_Tiles[ tile_id ].blending == QGears::B_SUBTRACT ) { vertex_buffer = m_SubtractVertexBuffer; } else if( m_Tiles[ tile_id ].blending == QGears::B_MULTIPLY ) { vertex_buffer = m_MultiplyVertexBuffer; } float* writeIterator = ( float* )vertex_buffer->lock( Ogre::HardwareBuffer::HBL_NORMAL ); writeIterator += m_Tiles[ tile_id ].start_vertex_index * TILE_VERTEX_INDEX_SIZE; writeIterator += 7; *writeIterator++ = u1; *writeIterator++ = v1; writeIterator += 7; *writeIterator++ = u2; *writeIterator++ = v1; writeIterator += 7; *writeIterator++ = u2; *writeIterator++ = v2; writeIterator += 7; *writeIterator++ = u1; *writeIterator++ = v1; writeIterator += 7; *writeIterator++ = u2; *writeIterator++ = v2; writeIterator += 7; *writeIterator++ = u1; *writeIterator++ = v2; vertex_buffer->unlock(); } //------------------------------------------------------------------------------ void Background2D::AddAnimation( Background2DAnimation* animation ) { m_Animations.push_back( animation ); } //------------------------------------------------------------------------------ void Background2D::PlayAnimation( const Ogre::String& animation, const Background2DAnimation::State state ) { bool found = false; for( unsigned int i = 0; i < m_Animations.size(); ++i ) { if( m_Animations[ i ]->GetName() == animation ) { found = true; m_Animations[ i ]->SetTime( 0 ); m_Animations[ i ]->AddTime( 0 ); } } for( unsigned int i = 0; i < m_AnimationPlayed.size(); ++i ) { if( m_AnimationPlayed[ i ].name == animation ) { m_AnimationPlayed.erase( m_AnimationPlayed.begin() + i ); } } if( found == true ) { AnimationPlayed anim; anim.name = animation; anim.state = state; m_AnimationPlayed.push_back( anim ); } else { LOG_ERROR( "Background2D doesn't has animation \"" + animation + "\"." ); } } //------------------------------------------------------------------------------ void Background2D::ScriptPlayAnimationLooped( const char* name ) { PlayAnimation( Ogre::String( name ), Background2DAnimation::LOOPED ); } //------------------------------------------------------------------------------ void Background2D::ScriptPlayAnimationOnce( const char* name ) { PlayAnimation( Ogre::String( name ), Background2DAnimation::ONCE ); } //------------------------------------------------------------------------------ int Background2D::ScriptAnimationSync( const char* animation ) { for( unsigned int i = 0; i < m_AnimationPlayed.size(); ++i ) { if( m_AnimationPlayed[ i ].name == animation ) { ScriptId script = ScriptManager::getSingleton().GetCurrentScriptId(); m_AnimationPlayed[ i ].sync.push_back( script ); return -1; } } return 1; } //------------------------------------------------------------------------------ void Background2D::renderQueueEnded( Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation ) { if( cv_show_background2d.GetB() == false ) { return; } if( queueGroupId == Ogre::RENDER_QUEUE_MAIN ) { m_RenderSystem->_setWorldMatrix( Ogre::Matrix4::IDENTITY ); m_RenderSystem->_setProjectionMatrix( Ogre::Matrix4::IDENTITY ); Ogre::Viewport *viewport( CameraManager::getSingleton().getViewport() ); float width = static_cast(viewport->getActualWidth()); float height = static_cast(viewport->getActualHeight()); Ogre::Matrix4 view; view.makeTrans( Ogre::Vector3( m_PositionReal.x * 2 / width, -m_PositionReal.y * 2 / height, 0 ) ); m_RenderSystem->_setViewMatrix( view ); if( m_AlphaRenderOp.vertexData->vertexCount != 0 ) { m_SceneManager->_setPass( m_AlphaMaterial->getTechnique( 0 )->getPass( 0 ), true, false ); m_RenderSystem->_render( m_AlphaRenderOp ); } if( m_AddRenderOp.vertexData->vertexCount != 0 ) { m_SceneManager->_setPass( m_AddMaterial->getTechnique( 0 )->getPass( 0 ), true, false ); m_RenderSystem->_render( m_AddRenderOp ); } if( m_SubtractRenderOp.vertexData->vertexCount != 0 ) { m_SceneManager->_setPass( m_SubtractMaterial->getTechnique( 0 )->getPass( 0 ), true, false ); m_RenderSystem->_render( m_SubtractRenderOp ); } if( m_MultiplyRenderOp.vertexData->vertexCount != 0 ) { m_SceneManager->_setPass( m_MultiplyMaterial->getTechnique( 0 )->getPass( 0 ), true, false ); m_RenderSystem->_render( m_MultiplyRenderOp ); } } } //------------------------------------------------------------------------------ void Background2D::CreateVertexBuffers() { m_AlphaMaxVertexCount = 2048 * TILE_VERTEX_COUNT; m_AlphaRenderOp.vertexData = new Ogre::VertexData; m_AlphaRenderOp.vertexData->vertexStart = 0; Ogre::VertexDeclaration* vDecl = m_AlphaRenderOp.vertexData->vertexDeclaration; size_t offset = 0; vDecl->addElement( 0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT4 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES ); m_AlphaVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer( vDecl->getVertexSize( 0 ), m_AlphaMaxVertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false ); m_AlphaRenderOp.vertexData->vertexBufferBinding->setBinding( 0, m_AlphaVertexBuffer ); m_AlphaRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; m_AlphaRenderOp.useIndexes = false; m_AddMaxVertexCount = 256 * TILE_VERTEX_COUNT; m_AddRenderOp.vertexData = new Ogre::VertexData; m_AddRenderOp.vertexData->vertexStart = 0; vDecl = m_AddRenderOp.vertexData->vertexDeclaration; offset = 0; vDecl->addElement( 0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT4 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES ); m_AddVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer( vDecl->getVertexSize( 0 ), m_AddMaxVertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false ); m_AddRenderOp.vertexData->vertexBufferBinding->setBinding( 0, m_AddVertexBuffer ); m_AddRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; m_AddRenderOp.useIndexes = false; m_SubtractMaxVertexCount = 256 * TILE_VERTEX_COUNT; // FIXME: 256? m_SubtractRenderOp.vertexData = new Ogre::VertexData; m_SubtractRenderOp.vertexData->vertexStart = 0; vDecl = m_SubtractRenderOp.vertexData->vertexDeclaration; offset = 0; vDecl->addElement( 0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT4 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES ); m_SubtractVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer( vDecl->getVertexSize( 0 ), m_SubtractMaxVertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false ); m_SubtractRenderOp.vertexData->vertexBufferBinding->setBinding( 0, m_SubtractVertexBuffer ); m_SubtractRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; m_SubtractRenderOp.useIndexes = false; m_MultiplyMaxVertexCount = 256 * TILE_VERTEX_COUNT; // FIXME: 256? m_MultiplyRenderOp.vertexData = new Ogre::VertexData; m_MultiplyRenderOp.vertexData->vertexStart = 0; vDecl = m_MultiplyRenderOp.vertexData->vertexDeclaration; offset = 0; vDecl->addElement( 0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT3 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE ); offset += Ogre::VertexElement::getTypeSize( Ogre::VET_FLOAT4 ); vDecl->addElement( 0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES ); m_MultiplyVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer( vDecl->getVertexSize( 0 ), m_MultiplyMaxVertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false ); m_MultiplyRenderOp.vertexData->vertexBufferBinding->setBinding( 0, m_AMultiplyVertexBuffer ); m_MultiplyRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; m_MultiplyRenderOp.useIndexes = false; } //------------------------------------------------------------------------------ void Background2D::DestroyVertexBuffers() { delete m_AlphaRenderOp.vertexData; m_AlphaRenderOp.vertexData = 0; m_AlphaVertexBuffer.setNull(); m_AlphaMaxVertexCount = 0; delete m_AddRenderOp.vertexData; m_AddRenderOp.vertexData = 0; m_AddVertexBuffer.setNull(); m_AddMaxVertexCount = 0; delete m_SubtractRenderOp.vertexData; m_SubtractRenderOp.vertexData = 0; m_SubtractVertexBuffer.setNull(); m_SubtractMaxVertexCount = 0; delete m_MultiplyRenderOp.vertexData; m_MultiplyRenderOp.vertexData = 0; m_MultiplyVertexBuffer.setNull(); m_MultiplyMaxVertexCount = 0; } //------------------------------------------------------------------------------ void Background2D::load( const QGears::Background2DFilePtr& background ) { assert( !background.isNull() ); background->load(); SetImage( background->getTextureName() ); m_virtual_screen_size = background->getClip(); SetRange( background->getRange() ); const Ogre::Vector3& position( background->getPosition() ); const Ogre::Quaternion& orientation( background->getOrientation() ); const Ogre::Radian& fov( background->getFov() ); CameraManager::getSingleton().Set2DCamera( position, orientation, fov ); load( background->getTiles() ); } //------------------------------------------------------------------------------ void Background2D::load( const QGears::Background2DFile::TileList& tiles ) { QGears::Background2DFile::TileList::const_iterator it( tiles.begin() ); QGears::Background2DFile::TileList::const_iterator it_end( tiles.end() ); size_t tile_index( 0 ); while( it != it_end ) { AddTile( *it ); load( tile_index++, it->animations ); ++it; } } //------------------------------------------------------------------------------ void Background2D::load( const size_t tile_index, const QGears::AnimationMap& animations ) { QGears::AnimationMap::const_iterator it( animations.begin() ); QGears::AnimationMap::const_iterator it_end( animations.end() ); while( it != it_end ) { const QGears::String& name( it->first ); const QGears::Animation& animation( it->second ); Background2DAnimation* anim( new Background2DAnimation( name, this, tile_index ) ); anim->SetLength( animation.length ); QGears::KeyFrameList::const_iterator itk( animation.key_frames.begin() ); QGears::KeyFrameList::const_iterator itk_end( animation.key_frames.end() ); while( itk != itk_end ) { anim->AddUVKeyFrame( *(itk++) ); } AddAnimation( anim ); ++it; } } //------------------------------------------------------------------------------