#include "sdlpp_scene.hpp" namespace SDLPP { Scene::Scene( std::shared_ptr< Renderer > &r ) : renderer( r ) { SDL_SetRenderDrawColor( renderer->getRendererPtr(), 0xFF, 0xFF, 0xFF, 0xFF ); prev_ticks = SDL_GetTicks(); } void Scene::addObject( const std::shared_ptr< RenderObject > &obj ) { std::lock_guard< std::mutex > lock( render_mutex ); render_objects.push_back( obj ); obj->setSceneID( ++max_object_id ); if ( obj->hasCollisions() ) { collision_objects.push_back( obj ); } if ( render_objects.size() == 1 ) { leftmost_obj = obj; rightmost_obj = obj; } else { auto rect = obj->getDoubleRect(); auto leftmost_rect = leftmost_obj->getDoubleRect(); if ( ( rect.first.getX() < leftmost_rect.first.getX() && !obj->getPermanent() ) || ( leftmost_obj->getPermanent() && !obj->getPermanent() ) ) leftmost_obj = obj; auto rightmost_rect = rightmost_obj->getDoubleRect(); if ( ( rect.first.getX() + rect.second.getX() > rightmost_rect.first.getX() + rightmost_rect.second.getX() && !obj->getPermanent() ) || ( rightmost_obj->getPermanent() && !obj->getPermanent() ) ) rightmost_obj = obj; } } void Scene::setZIndex( const std::shared_ptr< RenderObject > &obj, uint64_t index ) { std::lock_guard< std::mutex > guard( render_mutex ); int original_index = 0; for ( long unsigned int i = 0; i < render_objects.size(); i++ ) { if ( render_objects[i] == obj ) { original_index = i; } } if ( original_index == index ) return; if ( original_index > index ) original_index++; render_objects.insert( render_objects.begin() + index, obj ); render_objects.erase( render_objects.begin() + original_index ); } void Scene::moveDownZ( const std::shared_ptr< RenderObject > &obj ) { moveZ( obj, -1 ); } void Scene::moveUpZ( const std::shared_ptr< RenderObject > &obj ) { moveZ( obj, 1 ); } void Scene::moveZ( const std::shared_ptr< RenderObject > &obj, int addition ) { int original_index = 0; for ( long unsigned int i = 0; i < render_objects.size(); i++ ) { if ( render_objects[i] == obj ) { original_index = i; } } std::iter_swap( render_objects.begin() + original_index, render_objects.begin() + original_index + addition ); } void Scene::moveZTop( const std::shared_ptr< RenderObject > &obj ) { setZIndex( obj, render_objects.size() - 1 ); } void Scene::moveZBottom( const std::shared_ptr< RenderObject > &obj ) { setZIndex( obj, 0 ); } std::shared_ptr< RenderObject > Scene::getObject( int index ) { return render_objects[index]; } std::vector< std::shared_ptr< RenderObject > > Scene::getObjects() { return render_objects; } std::vector< std::shared_ptr< RenderObject > > Scene::getObjects( const std::unordered_set< int > &objectIDs ) { std::vector< std::shared_ptr< RenderObject > > ret{}; for ( const auto &x : render_objects ) { // check if object exists because of possible race condition if ( x && objectIDs.find( x->getId() ) != objectIDs.end() ) { ret.push_back( x ); } } return ret; } void Scene::updateScene() { // check for objects that should be removed checkKilled(); std::lock_guard< std::mutex > lock( render_mutex ); int now_ticks = SDL_GetTicks(); for ( const auto &x : render_objects ) { // move objects that should be moved x->move( now_ticks - prev_ticks ); // animate objects that should be animated x->animate( now_ticks - prev_ticks ); } prev_ticks = now_ticks; } std::vector< std::pair< uint64_t, std::shared_ptr< RenderObject > > > Scene::getCollisions( RenderObject &r ) { if ( r.getHidden() ) return {}; std::vector< std::pair< uint64_t, std::shared_ptr< RenderObject > > > ret{}; for ( const auto &x : collision_objects ) { for ( auto id : r.colidesWith( *x ) ) { ret.emplace_back( id, x ); } } return ret; } void Scene::visitCollisions( RenderObject &r, Visitor &v ) { for ( auto &collision : getCollisions( r ) ) { v.setFromId( collision.first ); collision.second->visit( v ); } } std::vector< std::pair< uint64_t, std::shared_ptr< RenderObject > > > Scene::getCollisions( RenderObject &r, const std::unordered_set< int > &objectIDs ) { if ( r.getHidden() ) return {}; std::vector< std::pair< uint64_t, std::shared_ptr< RenderObject > > > ret{}; for ( const auto &x : collision_objects ) { if ( objectIDs.find( x->getId() ) != objectIDs.end() ) { for ( auto id : r.colidesWith( *x ) ) { ret.push_back( { id, x } ); } } } return ret; } void Scene::renderScene( bool clear_renderer ) { checkKilled(); std::lock_guard< std::mutex > lock( render_mutex ); if ( clear_renderer ) SDL_RenderClear( renderer->getRendererPtr() ); if ( background && background->getTexturePtr() ) SDL_RenderCopy( renderer->getRendererPtr(), background->getTexturePtr(), NULL, NULL ); for ( const auto &x : render_objects ) { x->render(); } } void Scene::presentScene() { SDL_RenderPresent( renderer->getRendererPtr() ); } void Scene::setBackground( std::shared_ptr< Texture > bg ) { background = bg; } void Scene::setBackground( const std::string &img_path ) { background = std::make_shared< Texture >( renderer, img_path ); } void Scene::updateSizeAndPosition() { checkKilled(); std::lock_guard< std::mutex > lock( render_mutex ); for ( auto &x : render_objects ) { x->updateSizeAndPosition(); for ( auto &col : x->getCollisions() ) { col->updateCollision( x->collisionPushX(), x->collisionPushY(), x->collisionWidth(), x->collisionHeight(), x->getId() ); } } } void Scene::moveEverything( double x, double y ) { checkKilled(); std::lock_guard< std::mutex > lock( render_mutex ); for ( auto &obj : render_objects ) { if ( obj->getPermanent() ) continue; obj->setPos( obj->getDoubleRect().first + Vec2D< double >( x, y ) ); } } const std::shared_ptr< RenderObject > &Scene::leftmost() { return leftmost_obj; } const std::shared_ptr< RenderObject > &Scene::rightmost() { return rightmost_obj; } Vec2D< int > Scene::getDimensions() const { return renderer->getDimensions(); } int Scene::getWidth() const { return renderer->getWidth(); } int Scene::getHeight() const { return renderer->getHeight(); } Renderer &Scene::getRenderer() { return *renderer; } std::shared_ptr< Renderer > Scene::getRendererShared() { return renderer; } void Scene::setPrevTicks( int ticks ) { prev_ticks = ticks; } void Scene::saveScene() { saved_render_objects.clear(); saved_collision_objects.clear(); for ( auto &obj : render_objects ) { if ( !obj->isStatic() ) saved_render_objects.push_back( obj->copySelf() ); else saved_render_objects.push_back( obj ); } for ( auto &obj : collision_objects ) { if ( !obj->isStatic() ) saved_collision_objects.push_back( obj->copySelf() ); else saved_collision_objects.push_back( obj ); } } void Scene::resetScene() { render_objects.clear(); collision_objects.clear(); for ( auto &obj : saved_render_objects ) { if ( !obj->isStatic() ) render_objects.push_back( obj->copySelf() ); else render_objects.push_back( obj ); } for ( auto &obj : saved_collision_objects ) { if ( !obj->isStatic() ) collision_objects.push_back( obj->copySelf() ); else collision_objects.push_back( obj ); } } void Scene::checkKilled() { std::lock_guard< std::mutex > lock( render_mutex ); std::vector< int > killed; std::vector< int > killed_collisions; for ( long unsigned int i = 0; i < render_objects.size(); i++ ) { if ( render_objects[i]->getKilled() ) killed.push_back( i ); if ( i < collision_objects.size() && collision_objects[i]->getKilled() ) killed_collisions.push_back( i ); } // reverse so we don't screw up indexing while going thorugh the kill // indices std::reverse( killed.begin(), killed.end() ); std::reverse( killed_collisions.begin(), killed_collisions.end() ); for ( auto &index : killed ) { render_objects.erase( render_objects.begin() + index ); } for ( auto &index : killed_collisions ) { collision_objects.erase( collision_objects.begin() + index ); } } } // namespace SDLPP