DejaVu |
» 2025-09-03 11:59:59 Przetestuj na boku w małym programie jeżeli masz takie podejrzenie. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-03 12:15:03 Znalazłem kilka błędów z obsługą eventów lasso i je naprawiłem ale bug i tak występuje: Poniżej zamieszczam testowy program jak radził DejaVu. Kod można śmiało uruchomić - jest kompletny  #include <iostream> #include <string> #include <functional> #define NOMINMAX #include <Windows.h> #include <SFML/Graphics.hpp>
sf::RenderWindow * window; sf::Vector2i mousePosition; sf::Vector2f worldMousePosition;
float zoom = 2; float zoom_delta = 2; sf::Vector2i canvasSize; sf::Vector2f canvasPosition; sf::Sprite canvasSprite; sf::Color lasso_color = sf::Color( 255, 127, 127, 255 );
sf::Vector2i worldToTile( sf::Vector2f p, sf::Vector2f canvasPosition, sf::Vector2i size, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = p - canvasPosition; int tx = std::clamp( int( std::floor( local.x / scale ) ), 0, size.x - 1 ); int ty = std::clamp( int( std::floor( local.y / scale ) ), 0, size.y - 1 ); return sf::Vector2i( tx, ty ); }
sf::Vector2i selectionToTile( sf::Vector2f p, sf::Vector2f canvasPosition, sf::Vector2i canvas_size, sf::Vector2i selection_size, sf::Vector2i selection_offset, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = p - canvasPosition; int tx = std::clamp( int( std::floor( local.x / scale ) ), - selection_size.x + selection_offset.x, canvas_size.x + selection_offset.x ); int ty = std::clamp( int( std::floor( local.y / scale ) ), - selection_size.y + selection_offset.y, canvas_size.y + selection_offset.y ); return sf::Vector2i( tx, ty ); }
sf::Vector2i worldToTile( sf::Vector2f p, sf::Vector2f canvasPosition, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = p - canvasPosition; int tx = int( std::floor( local.x / scale ) ); int ty = int( std::floor( local.y / scale ) ); return sf::Vector2i( tx, ty ); }
enum class LassoState { None, Selecting, Selected, Moving };
class Lasso { public: LassoState state; std::vector < sf::Vector2i > points; sf::Vector2i offset; sf::Image * image; sf::Texture texture; sf::Sprite sprite; sf::RenderTexture mask; sf::Sprite maskSprite; sf::Vector2i maskOffset; sf::IntRect rect; Lasso() { state = LassoState::None; points.clear(); offset = sf::Vector2i( 0, 0 ); image = nullptr; rect = sf::IntRect( 0, 0, 0, 0 ); maskOffset = sf::Vector2i( 0, 0 ); } ~Lasso() { } void shiftOriginIfNeeded( sf::Vector2i & point ) { sf::Vector2i shift( 0, 0 ); if( point.x < 0 ) { shift.x = point.x; point.x = 0; } if( point.y < 0 ) { shift.y = point.y; point.y = 0; } if( shift.x != 0 || shift.y != 0 ) { maskOffset += shift; for( auto & p: points ) p -= shift; } } void addPoint( sf::Vector2i point ) { point = point - maskOffset; shiftOriginIfNeeded( point ); if( points.empty() || std::hypot( float( points.back().x - point.x ), float( points.back().y - point.y ) ) >= 1.0f ) { points.push_back( point ); } } void unselect() { points.clear(); generateRect(); } void generateRect() { if( points.size() > 2 ) { int minX = std::numeric_limits < int >::max(); int maxX = std::numeric_limits < int >::lowest(); int minY = std::numeric_limits < int >::max(); int maxY = std::numeric_limits < int >::lowest(); for( auto & p: points ) { minX = std::min( minX, p.x ); maxX = std::max( maxX, p.x ); minY = std::min( minY, p.y ); maxY = std::max( maxY, p.y ); } int left = minX + maskOffset.x; int top = minY + maskOffset.y; int width =( maxX - minX + 1 ); int height =( maxY - minY + 1 ); if( width > 0 && height > 0 ) rect = sf::IntRect( left, top, width, height ); else rect = sf::IntRect( 0, 0, 0, 0 ); } else { rect = sf::IntRect( 0, 0, 0, 0 ); } } bool clickOnSelection( sf::Vector2i point ) { return rect.contains( point ); } void generateOutline( float scale ) { if( points.size() < 3 ) return; sf::VertexArray lines( sf::LineStrip ); for( auto & p: points ) lines.append( sf::Vertex( sf::Vector2f( p ), lasso_color ) ); if( image != nullptr ) { texture = sf::Texture(); texture.setSmooth( false ); texture.setRepeated( false ); texture.create( rect.getSize().x, rect.getSize().y ); texture.loadFromImage( * image ); mask.create( texture.getSize().x, texture.getSize().y ); mask.clear( sf::Color( 127, 47, 47, 127 ) ); sf::RenderStates rs; rs.blendMode = sf::BlendNone; rs.transform.translate( 0.5f, 0.5f ); mask.draw( lines, rs ); mask.display(); } } void drawOutline( sf::Vector2f canvasPosition, float scale ) { maskSprite = sf::Sprite( mask.getTexture() ); maskSprite.setScale( scale, scale ); maskSprite.setPosition( canvasPosition + sf::Vector2f( maskOffset ) * scale ); window->draw( maskSprite ); } void draw( sf::Vector2f canvasPosition, float scale ) { if( points.size() >= 3 ) { if( true ) { generateOutline( scale ); drawOutline( canvasPosition, scale ); } } } };
Lasso * lasso = nullptr;
int main() { window = new sf::RenderWindow( sf::VideoMode( 800, 600 ), "test program lasso", sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close ); canvasSize = sf::Vector2i( 64, 64 ); canvasPosition =( sf::Vector2f( window->getSize() ) / 2.0f - sf::Vector2f( canvasSize / 2 ) * zoom * zoom_delta ); lasso = new Lasso(); while( window->isOpen() ) { mousePosition = sf::Mouse::getPosition( * window ); worldMousePosition = window->mapPixelToCoords( mousePosition ); sf::Event event; while( window->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window->close(); if( event.type == sf::Event::MouseMoved && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { if( lasso->state == LassoState::Moving ) { sf::Vector2i tile = selectionToTile( worldMousePosition, canvasPosition, canvasSize, lasso->rect.getSize(), lasso->offset, zoom, zoom_delta ); sf::Vector2i dst = tile - lasso->offset; lasso->maskOffset.x = dst.x; lasso->maskOffset.y = dst.y; lasso->generateRect(); } else if( lasso->state == LassoState::Selecting ) { sf::Vector2i tile = worldToTile( worldMousePosition, canvasPosition, canvasSize, zoom, zoom_delta ); if( lasso->image != nullptr ) { lasso->image = nullptr; } lasso->addPoint( tile ); lasso->generateRect(); lasso->image = new sf::Image(); lasso->image->create( lasso->rect.width, lasso->rect.height, sf::Color::Transparent ); } } if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) { if( lasso->state == LassoState::Selecting ) { lasso->state = LassoState::Selected; } else if( lasso->state == LassoState::Moving ) { lasso->state = LassoState::Selected; } } if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) { sf::Vector2i tile = worldToTile( worldMousePosition, canvasPosition, zoom, zoom_delta ); if( lasso->clickOnSelection( tile ) ) { lasso->state = LassoState::Moving; lasso->offset = tile - lasso->maskOffset; if( lasso->image == nullptr ) { lasso->image = new sf::Image(); lasso->generateRect(); lasso->image->create( lasso->rect.width, lasso->rect.height, sf::Color::Transparent ); } } else if( canvasSprite.getGlobalBounds().contains( worldMousePosition ) ) { if( lasso->image != nullptr ) { lasso->generateRect(); lasso->image = nullptr; } lasso->state = LassoState::Selecting; lasso->unselect(); lasso->maskOffset = tile; } else { if( lasso->image != nullptr ) { lasso->generateRect(); lasso->image = nullptr; } lasso->state = LassoState::None; lasso->unselect(); } } } window->clear( sf::Color( 56, 56, 56 ) ); sf::Image empty_image; empty_image.create( canvasSize.x, canvasSize.y, sf::Color( 127, 127, 127 ) ); sf::Texture empty_tex = sf::Texture(); empty_tex.loadFromImage( empty_image ); canvasSprite = sf::Sprite( empty_tex ); canvasSprite.setPosition( canvasPosition ); canvasSprite.setScale( zoom * zoom_delta, zoom * zoom_delta ); window->draw( canvasSprite ); lasso->draw( canvasPosition, zoom * zoom_delta ); window->display(); } return 0; }
|
|
pekfos |
» 2025-09-03 23:34:43 U mnie działa rs.transform.translate( 0.5f, 0.5f ); Możesz pokombinować z tymi wartościami, np zmniejszyć je do 0.25f czy czegoś takiego. Problem jest w tym że chcesz użyć karty graficznej do generowania obrazu dokładnego co do piksela, a ta nie jest do tego przystosowana. Renderowanie robisz w koordynatach "świata" i chcesz wylądować w bardzo konkretne piksele na "ekranie", ta translacja o ułamek piksela ma na celu sprawienie by współrzędne celowały w środki pikseli, a nie ich rogi, żeby błędy obliczeń nie sprawiły że zapalą się piksele obok. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-03 23:36:28 U mnie zazwyczaj też działa, ale co jakiś czas występuje bug |
|
pekfos |
» 2025-09-03 23:40:39 To podaj jak zreprodukować problem. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-03 23:49:04 Aby wystąpił bug należy zaznaczyć kształt kolisty w kierunku przeciwnym do ruchu wskazówek zegara. Należy to zrobić w miarę powoli, żeby bug wystąpił. Ruch powinien trwać 0.5-1 sekundy. Gdy bug nie wystąpi należy ponowić działanie aż do wystąpienia buga. |
|
pekfos |
» 2025-09-04 00:07:06 int left = minX + maskOffset.x; int top = minY + maskOffset.y; int width =( maxX - minX + 1 ); int height =( maxY - minY + 1 ); Jeżeli tekstura ma tak określony wymiar, minX i minY muszą być zerowe. Bug występuje gdy nie są. maskOffset powinno być równe minimalnym współrzędnym, nie wiem po co masz to cały czas utrzymywane osobno. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-04 13:52:32 Dobra, już usunąłem minX, minY. poprawiony fragment kodu:void generateRect() { if( points.size() < 3 ) { rect = sf::IntRect( 0, 0, 0, 0 ); return; } int maxX = std::numeric_limits < int >::lowest(); int maxY = std::numeric_limits < int >::lowest(); for( auto & p: points ) { maxX = std::max( maxX, p.x ); maxY = std::max( maxY, p.y ); } int left = maskOffset.x; int top = maskOffset.y; int width = maxX; int height = maxY; if( width > 0 && height > 0 ) { rect = sf::IntRect( left, top, width, height ); } else { rect = sf::IntRect( 0, 0, 0, 0 ); } }
cały kod:#include <iostream> #include <string> #include <functional> #define NOMINMAX #include <Windows.h> #include <SFML/Graphics.hpp>
sf::RenderWindow * window; sf::Vector2i mousePosition; sf::Vector2f worldMousePosition;
float zoom = 2; float zoom_delta = 2; sf::Vector2i canvasSize; sf::Vector2f canvasPosition; sf::Sprite canvasSprite; sf::Color lasso_color = sf::Color( 255, 127, 127, 255 );
sf::Vector2i worldToTile( sf::Vector2f cursorPosition, sf::Vector2f canvasPosition, sf::Vector2i size, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = cursorPosition - canvasPosition; int tx = std::clamp( int( std::floor( local.x / scale ) ), 0, size.x - 1 ); int ty = std::clamp( int( std::floor( local.y / scale ) ), 0, size.y - 1 ); return sf::Vector2i( tx, ty ); }
sf::Vector2i selectionToTile( sf::Vector2f cursorPosition, sf::Vector2f canvasPosition, sf::Vector2i canvas_size, sf::Vector2i selection_size, sf::Vector2i selection_offset, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = cursorPosition - canvasPosition; int tx = std::clamp( int( std::floor( local.x / scale ) ), - selection_size.x + selection_offset.x, canvas_size.x + selection_offset.x ); int ty = std::clamp( int( std::floor( local.y / scale ) ), - selection_size.y + selection_offset.y, canvas_size.y + selection_offset.y ); return sf::Vector2i( tx, ty ); }
sf::Vector2i worldToTile( sf::Vector2f cursorPosition, sf::Vector2f canvasPosition, float zoom, float zoom_delta ) { float scale = zoom * zoom_delta; sf::Vector2f local = cursorPosition - canvasPosition; int tx = int( std::floor( local.x / scale ) ); int ty = int( std::floor( local.y / scale ) ); return sf::Vector2i( tx, ty ); }
enum class LassoState { None, Selecting, Selected, Moving };
class Lasso { public: LassoState state; std::vector < sf::Vector2i > points; sf::Vector2i offset; sf::Image * image; sf::Texture texture; sf::Sprite sprite; sf::RenderTexture mask; sf::Sprite maskSprite; sf::Vector2i maskOffset; sf::IntRect rect; Lasso() { state = LassoState::None; points.clear(); offset = sf::Vector2i( 0, 0 ); image = nullptr; rect = sf::IntRect( 0, 0, 0, 0 ); maskOffset = sf::Vector2i( 0, 0 ); } ~Lasso() { } void shiftOriginIfNeeded( sf::Vector2i & point ) { sf::Vector2i shift( 0, 0 ); if( point.x < 0 ) { shift.x = point.x; point.x = 0; } if( point.y < 0 ) { shift.y = point.y; point.y = 0; } if( shift.x != 0 || shift.y != 0 ) { maskOffset += shift; for( auto & p: points ) p -= shift; } } void addPoint( sf::Vector2i point ) { point = point - maskOffset; shiftOriginIfNeeded( point ); if( points.empty() || std::hypot( float( points.back().x - point.x ), float( points.back().y - point.y ) ) >= 1.0f ) { points.push_back( point ); } } void unselect() { points.clear(); generateRect(); } void generateRect() { if( points.size() < 3 ) { rect = sf::IntRect( 0, 0, 0, 0 ); return; } int maxX = std::numeric_limits < int >::lowest(); int maxY = std::numeric_limits < int >::lowest(); for( auto & p: points ) { maxX = std::max( maxX, p.x ); maxY = std::max( maxY, p.y ); } int left = maskOffset.x; int top = maskOffset.y; int width = maxX; int height = maxY; if( width > 0 && height > 0 ) { rect = sf::IntRect( left, top, width, height ); } else { rect = sf::IntRect( 0, 0, 0, 0 ); } } bool clickOnSelection( sf::Vector2i point ) { return rect.contains( point ); } void generateOutline( float scale ) { if( points.size() < 3 ) return; sf::VertexArray lines( sf::LineStrip ); for( auto & p: points ) lines.append( sf::Vertex( sf::Vector2f( p ), lasso_color ) ); if( image != nullptr ) { texture = sf::Texture(); texture.setSmooth( false ); texture.setRepeated( false ); texture.create( rect.getSize().x, rect.getSize().y ); texture.loadFromImage( * image ); mask.create( texture.getSize().x, texture.getSize().y ); mask.clear( sf::Color( 127, 47, 47, 127 ) ); sf::RenderStates rs; rs.blendMode = sf::BlendNone; rs.transform.translate( 0.5f, 0.5f ); mask.draw( lines, rs ); mask.display(); } } void drawOutline( sf::Vector2f canvasPosition, float scale ) { maskSprite = sf::Sprite( mask.getTexture() ); maskSprite.setScale( scale, scale ); maskSprite.setPosition( canvasPosition + sf::Vector2f( maskOffset ) * scale ); window->draw( maskSprite ); } void draw( sf::Vector2f canvasPosition, float scale ) { if( points.size() >= 3 ) { if( true ) { generateOutline( scale ); drawOutline( canvasPosition, scale ); } } } };
Lasso * lasso = nullptr;
int main() { window = new sf::RenderWindow( sf::VideoMode( 800, 600 ), "test program lasso", sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close ); canvasSize = sf::Vector2i( 64, 64 ); canvasPosition =( sf::Vector2f( window->getSize() ) / 2.0f - sf::Vector2f( canvasSize / 2 ) * zoom * zoom_delta ); lasso = new Lasso(); while( window->isOpen() ) { mousePosition = sf::Mouse::getPosition( * window ); worldMousePosition = window->mapPixelToCoords( mousePosition ); sf::Event event; while( window->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window->close(); if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) { if( lasso->state == LassoState::Selecting ) { lasso->state = LassoState::Selected; } else if( lasso->state == LassoState::Moving ) { lasso->state = LassoState::Selected; } } if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) { sf::Vector2i tile = worldToTile( worldMousePosition, canvasPosition, zoom, zoom_delta ); if( lasso->clickOnSelection( tile ) ) { lasso->state = LassoState::Moving; lasso->offset = tile - lasso->maskOffset; if( lasso->image == nullptr ) { lasso->image = new sf::Image(); lasso->generateRect(); lasso->image->create( lasso->rect.width, lasso->rect.height, sf::Color::Transparent ); } } else if( canvasSprite.getGlobalBounds().contains( worldMousePosition ) ) { if( lasso->image != nullptr ) { lasso->generateRect(); lasso->image = nullptr; } lasso->state = LassoState::Selecting; lasso->unselect(); lasso->maskOffset = tile; } else { if( lasso->image != nullptr ) { lasso->generateRect(); lasso->image = nullptr; } lasso->state = LassoState::None; lasso->unselect(); } } } if( sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { if( lasso->state == LassoState::Moving ) { sf::Vector2i tile = selectionToTile( worldMousePosition, canvasPosition, canvasSize, lasso->rect.getSize(), lasso->offset, zoom, zoom_delta ); sf::Vector2i dst = tile - lasso->offset; lasso->maskOffset.x = dst.x; lasso->maskOffset.y = dst.y; lasso->generateRect(); } else if( lasso->state == LassoState::Selecting ) { sf::Vector2i tile = worldToTile( worldMousePosition, canvasPosition, canvasSize, zoom, zoom_delta ); if( lasso->image != nullptr ) { lasso->image = nullptr; } lasso->addPoint( tile ); lasso->generateRect(); lasso->image = new sf::Image(); lasso->image->create( lasso->rect.width, lasso->rect.height, sf::Color::Transparent ); } } window->clear( sf::Color( 56, 56, 56 ) ); sf::Image empty_image; empty_image.create( canvasSize.x, canvasSize.y, sf::Color( 127, 127, 127 ) ); sf::Texture empty_tex = sf::Texture(); empty_tex.loadFromImage( empty_image ); canvasSprite = sf::Sprite( empty_tex ); canvasSprite.setPosition( canvasPosition ); canvasSprite.setScale( zoom * zoom_delta, zoom * zoom_delta ); window->draw( canvasSprite ); lasso->draw( canvasPosition, zoom * zoom_delta ); window->display(); } return 0; }
|
|
1 2 3 « 4 » 5 |