tBane Temat założony przez niniejszego użytkownika |
» 2025-09-04 16:49:58 Spróbowałem jeszcze raz z ChatemGPT i dał mi rozwiązanie. Wystarczyło domknąć zaznaczenie lasso, by poprawnie renderowało zaznaczenie tzn. teraz już nie ma tego przesunięcia o 1px. No ale toz kolei ogranicza użytkownika w zaznaczaniu kształtu ... Jak sądzicie, zostawić tak ? W Paint'cie to wygląda inaczej - zaznaczenie jest domykane po zakończeniu zaznaczania a nie w trakcie.. To tak jakby ostatniej linii nie chciało rysować :-/ #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( const auto & p: points ) { maxX = std::max( maxX, p.x ); maxY = std::max( maxY, p.y ); } int w = maxX + 1; int h = maxY + 1; rect = sf::IntRect( maskOffset.x, maskOffset.y, w, h ); } bool clickOnSelection( sf::Vector2i point ) { return rect.contains( point ); } void generateOutline( float scale ) { if( points.size() < 3 ) return; if( rect.width <= 0 || rect.height <= 0 ) return; if( mask.getSize() != sf::Vector2u( rect.width, rect.height ) ) mask.create( rect.width, rect.height ); mask.clear( sf::Color( 127, 47, 47, 127 ) ); sf::VertexArray lines( sf::LineStrip ); for( auto & point: points ) lines.append( sf::Vertex( sf::Vector2f( point ), lasso_color ) ); lines.append( sf::Vertex( sf::Vector2f( points.front() ), lasso_color ) ); sf::RenderStates rs; rs.blendMode = sf::BlendAlpha; 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( float( rect.left ), float( rect.top ) ) * 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; }
|
|
DejaVu |
» 2025-09-04 17:21:45 Sam jesteś sobie product ownerem więc musisz podjąć decyzję czy użytkownikom, którzy będą korzystali z tego narzędzia będzie obecna postać przeszkadzała czy nie. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-04 17:28:55 Kurde, chciałbym jednak bez tego łączenia :-/ ale nie wiem jak to zrobić :-/ Więc chyba zostawię tak jak jest obecnie :-/ |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-04 20:42:00 Zlokalizowałem buga. To sf::VertexArray(sf::LineStrip); jest odpowiedzialny za błędne renderowanie ostatniej linii stąd ten brakujący piksel |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-05 13:34:18 Problem rozwiązany. Dodałem sf::VertexArray p(sf::Points) dla pierwszego i ostatniego punktu no i te punkty są rysowany na masce :-)  #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( const auto & p: points ) { maxX = std::max( maxX, p.x ); maxY = std::max( maxY, p.y ); } int w = maxX + 1; int h = maxY + 1; rect = sf::IntRect( maskOffset.x, maskOffset.y, w, h ); } bool clickOnSelection( sf::Vector2i point ) { return rect.contains( point ); } void generateOutline( bool selectionComplete = false ) { if( points.size() < 3 ) return; if( rect.width <= 0 || rect.height <= 0 ) return; if( mask.getSize() != sf::Vector2u( rect.width, rect.height ) ) mask.create( rect.width, rect.height ); mask.clear( sf::Color( 127, 47, 47, 127 ) ); sf::VertexArray lines( sf::LineStrip ); for( auto & point: points ) lines.append( sf::Vertex( sf::Vector2f( point ), lasso_color ) ); sf::VertexArray p( sf::Points ); p.append( sf::Vertex( sf::Vector2f( points.front() ), lasso_color ) ); p.append( sf::Vertex( sf::Vector2f( points.back() ), lasso_color ) ); if( selectionComplete ) lines.append( sf::Vertex( sf::Vector2f( points.front() ), lasso_color ) ); sf::RenderStates rs; rs.blendMode = sf::BlendAlpha; rs.transform.translate( 0.5f, 0.5f ); mask.draw( lines, rs ); mask.draw( p, rs ); mask.display(); } void drawOutline( sf::Vector2f canvasPosition, float scale ) { maskSprite = sf::Sprite( mask.getTexture() ); maskSprite.setScale( scale, scale ); maskSprite.setPosition( canvasPosition + sf::Vector2f( float( rect.left ), float( rect.top ) ) * scale ); window->draw( maskSprite ); } void draw( sf::Vector2f canvasPosition, float scale ) { if( points.size() >= 3 ) { if( state == LassoState::Selecting ) { generateOutline( false ); drawOutline( canvasPosition, scale ); } if( state == LassoState::Selected || state == LassoState::Moving ) { generateOutline( true ); 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; }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-09-06 17:18:21 Następnie można wygenerować maskę takiego zaznaczenia korzystając z sf::ConvexShape. Poniżej podaję przykład. Temat Wyczerpany :-) sf::RenderTexture * generateMask() { sf::RenderTexture * mask = new sf::RenderTexture(); mask->create( image->getSize().x, image->getSize().y ); std::cout << image->getSize().x << ", " << image->getSize().y << "\n"; if( points.size() >= 3 ) { mask->clear( sf::Color::Transparent ); sf::ConvexShape poly; poly.setPointCount( points.size() ); for( std::size_t i = 0; i < points.size(); ++i ) poly.setPoint( i, sf::Vector2f( points[ i ] ) ); poly.setFillColor( sf::Color::White ); poly.setOutlineThickness( 0.5f ); poly.setOutlineColor( sf::Color::White ); sf::RenderStates st; st.blendMode = sf::BlendNone; st.transform.translate( 0.5f, 0.5f ); mask->draw( poly, st ); } else { mask->clear( sf::Color::White ); } mask->display(); mask->setSmooth( false ); return mask; }
|
|
1 2 3 4 « 5 » |