Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: GetPixel() in 2.1?  (Read 5723 times)

0 Members and 1 Guest are viewing this topic.

Derp

  • Newbie
  • *
  • Posts: 9
    • View Profile
GetPixel() in 2.1?
« on: January 18, 2014, 01:17:36 pm »
Hello!
What am I trying to do is to invent a bicycle make a click detection on isometric tiles. My current approach:
Map::ClickOn(sf::Vector2f pos){
        for(int i = 0; i < 100; i++){
                for(int j = 0; j < 100; j++){
                        if(tiles[i][j].getGlobalBounds().contains(pos)){
                                std::cout<<"Selected tile @ "<<i<<", "<<j<<std::endl;
                                return;
                        }
                }
        }
where 'pos' is the mouse click position. In 3D I'd simply cast a ray but with 2D there are overlapping bounding boxes so it often detects neighbouring tiles.
I thought that I can get all sprites with their bounding boxes are within 'pos' and omit the ones with transparent pixels on click position. sf::Sprite had GetPixel(x,y) method back in 1.6 but now it's gone. Is there any ways to check the color of sprite's each pixel? Or maybe a simplier approach to solve this problem?

TY!
« Last Edit: January 18, 2014, 01:19:55 pm by Derp »

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: GetPixel() in 2.1?
« Reply #1 on: January 18, 2014, 01:50:06 pm »
Seems like you can solve this problem by transforming mouse position:
http://stackoverflow.com/questions/6915555/how-to-transform-mouse-location-in-isometric-tiling-map
SFML.Utils - useful extensions for SFML.Net

Derp

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: GetPixel() in 2.1?
« Reply #2 on: January 18, 2014, 02:37:51 pm »
If I understand this correctly, it'll work out just for tiles. But they're all the same size. What if there are different shaped objects? for ex. a tree sprite? Bounding box wont let to click behind and will catch clicks on that tree - that's why I thought about excluding transparent pixels.

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: GetPixel() in 2.1?
« Reply #3 on: January 18, 2014, 06:16:36 pm »
I see. Then you could try:
http://sfml-dev.org/documentation/2.1/classsf_1_1Texture.php#aefc19bcd95565dd2348fd4cec0facddc

But you will have to transform from sprite to texture yourself. Also, that method is pretty slow, so I recommend using it once per texture and then accesing images via map:
http://www.cplusplus.com/reference/map/map/
SFML.Utils - useful extensions for SFML.Net

Derp

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: GetPixel() in 2.1?
« Reply #4 on: January 18, 2014, 07:27:05 pm »
I see. Then you could try:
http://sfml-dev.org/documentation/2.1/classsf_1_1Texture.php#aefc19bcd95565dd2348fd4cec0facddc
Ha-ha, actually I came to such idea by myself like 40 minutes ago but I kinda missed the copyToImage() :D
Thanks, I'll give it a try!
---
                        if(tiles[i][j].getGlobalBounds().contains(pos)){
                                sf::Image img = tiles[i][j].getTexture()->copyToImage();
                                sf::Vector2f tilePos = tiles[i][j].getPosition();
                                sf::Color c = img.getPixel(pos.x - tilePos.x, pos.y - tilePos.y);
                                if(c.a != 0){
                                        std::cout<<"Selected tile @ "<<i<<", "<<j<<std::endl;
                                        return;
                                }
                        }
Idk how this solution impacts performance-wise, with 10k tiles it works well. Maybe I should store all images for all of my textures separately.
Thanks again!~
« Last Edit: January 18, 2014, 08:01:59 pm by Derp »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: GetPixel() in 2.1?
« Reply #5 on: January 18, 2014, 09:18:38 pm »
It's definitely a bad idea to download texture data from the graphics card into an sf::Image every time you click.

Why don't you precompute the images? You don't need 32 bit per pixel anyway, that's a total waste of memory. 1 bit is enough to determine whether a pixel is transparent or not. You could use std::vector<bool> (or something else if you don't like this one) to store a texture as a bitset. Ideally, you directly do that when loading:
sf::Image image;
if (!image.loadFromFile(...))
    ... // error

std::vector<bool> bitset = computeBitset(image);

sf::Texture texture;
if (!texture.loadFromImage(image))
    ... // error
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Derp

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: GetPixel() in 2.1?
« Reply #6 on: January 18, 2014, 10:55:37 pm »
Hi Nexus, thank you for your reply.
I thought about 1bpp data and I've tried but FPS actually lower than with simple Image->getPixel(x,y). Maybe I'm doing something wrong?

std::map<std::string, std::vector<bool>> bitsets; //string contains texture name

after loading the image & texture I create the bitset for this texture:
bitsets[texturename] = calculateBitset(images[texturename]);

std::vector<bool> calculateBitset(sf::Image img){
        sf::Vector2u imgSize = img.getSize();
        std::vector<bool> retVal;
        for(int i = 0; i < imgSize.x; i++){
                for(int j = 0; j < imgSize.y; j++){
                        retVal.push_back(img.getPixel(i,j).a != 255); //false = transparent
                }
        }
        return retVal;
}
then I check if given point is clickable:
bool isClickable(std::string textureName, sf::Vector2u pos){
        int w = images[textureName].getSize().x;
        return !bitsets[textureName][w*pos.y+pos.x];
}
With this code I'm experiencing 6-20 FPS drop (depending on map indexes)

If I load and store only sf::Images and call getPixel() every time, FPS drop is only 1-6 and equally lower cpu load.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: GetPixel() in 2.1?
« Reply #7 on: January 19, 2014, 12:51:33 pm »
Really? That's very strange. What if you try std::vector<char> instead of std::vector<bool>? You can leave most of the code, just store either the value 0 or 1 per char.

And you should make sure you don't copy unnecessarily. For example, pass sf::Image and std::string by const-reference, not by value. You could also make isClickable() const, i.e. use map::find() instead of map::operator[].

For example (try also with char):
std::vector<bool> calculateBitset(const sf::Image& img)
{
        sf::Vector2u imgSize = img.getSize();

        std::vector<bool> retVal(imgSize.x * imgSize.y); // allocate directly

        for (unsigned int i = 0; i < imgSize.x; ++i) // unsigned,  pre-increment (not crucial
                for (unsigned int j = 0; j < imgSize.y; ++j) // here, but generally good practice)
                        retVal[imgSize.x*j + i] = (img.getPixel(i, j).a != 255);

        return retVal;
}
« Last Edit: January 19, 2014, 12:59:01 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Derp

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: GetPixel() in 2.1?
« Reply #8 on: January 20, 2014, 12:51:50 am »
I did this and in release configuration everything works much better. Also now I use const& every time when possible. But I think it can be optimised further and it may start lagging when thee will be like 3 layers on the map.

And you should make sure you don't copy unnecessarily. For example, pass sf::Image and std::string by const-reference, not by value. You could also make isClickable() const, i.e. use map::find() instead of map::operator[].

Isn't operator[] faster than find()?

TY again!

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: GetPixel() in 2.1?
« Reply #9 on: January 20, 2014, 10:03:17 am »
No, find() only performs a lookup. operator[] also inserts an element if it is not found, so the semantics are different.

See also http://en.cppreference.com/w/cpp/container/map
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything