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

Author Topic: update texture from a sf::image  (Read 3485 times)

0 Members and 1 Guest are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
update texture from a sf::image
« on: April 21, 2016, 03:37:41 am »
Hi Folks,

So I have a sf::Image that I update. The image is quite large 5680 X 4178, so when I update the sf::Image, I ensure to pass in the sf::IntRect of the area that I am working on - see below. This works fine for my needs and it is pretty fast to update the IntRect area. (0.047 secs).

//set Pixel colour for all pixels in regionIntRect that match colourToCheck
void drawEngine::setImagePixelColour(sf::Image *passed_Image, sf::Color colourToCheck, sf::Color colourToSet, sf::IntRect regionIntRect)
{
        for (int y = regionIntRect.top; y < (regionIntRect.height + regionIntRect.top); y++)
        {
                for (int x = regionIntRect.left; x < (regionIntRect.width + regionIntRect.left); x++)
                {
                        if (passed_Image->getPixel(x, y) == colourToCheck)
                        {
                                passed_Image->setPixel(x, y, colourToSet);
                        }
                }
        }
}
 

However I am finding that update texture command is a bit slower. (0.27 secs) to run the below. Now I know the sf::Texture update method is having to load into the graphics memory so it will always be slower.

(regionLandHighlightTexture is the sf::Texture and landHighlightImageToDisplay is the sf::Image that I modified via the above method.)

regionLandHighlightTexture.update(landHighlightImageToDisplay);
 

Now I know the sf::Texture update method is having to load into the graphics memory so it will always be slower. I was wondering if there was a way to make to the update faster.

Basically I know the area of the texture that needs updating from the IntRect that I modified. However when I check the update methods, I don't see one where I can pass in an IntRect, i.e. only update this portion. I do see this method which is very similiar.

(What does "x   X offset in the texture where to copy the source image" mean in regards to this method?)

void    update (const Uint8 *pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)

However I don't understand how I can get an array of pixels from my sf::Image using the sf::IntRect that I modified. I don't see any method that can pull out an array of pixels using sf::IntRect as part of the sf::Image class. I do see the below method but I don't really understand what it is doing. It seems to be pulling out the entire sf::Image pixel array? Whereas I only want a small portion of the sf::Image pixel array.

const Uint8 *    getPixelsPtr () const

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: update texture from a sf::image
« Reply #1 on: April 21, 2016, 08:46:30 am »
What exactly are you doing with the sf::Image? Do you really have to go the slow way via sf::Image? Can't it be done with an sf::RenderTexture or a shader?

To update only part of the texture, you'd have to extract that part from your sf::Image. You could construct the std::vector<sf::Uint8> in the same loop and then pass it to update.

void drawEngine::setImagePixelColour(std::vector<sf::Uint8>& passed_vector, sf::Image& passed_Image, sf::Color colourToCheck, sf::Color colourToSet, sf::IntRect regionIntRect)
{
    passed_vector.clear();

    for (int y = regionIntRect.top; y < (regionIntRect.height + regionIntRect.top); y++)
    {
        for (int x = regionIntRect.left; x < (regionIntRect.width + regionIntRect.left); x++)
        {
            if (passed_Image.getPixel(x, y) == colourToCheck)
            {
                passed_Image.setPixel(x, y, colourToSet);
                passed_vector.emplace_back(colourToSet.r);
                passed_vector.emplace_back(colourToSet.g);
                passed_vector.emplace_back(colourToSet.b);
                passed_vector.emplace_back(colourToSet.a);
            }
        }
    }
}
// ...
texture.update(vector.data(), region.width, region.height, region.left, region.top);

As side note: Use references and not pointers to pass around objects (see my code above).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: update texture from a sf::image
« Reply #2 on: April 21, 2016, 09:14:26 am »
Don't forget passed_vector.reserve(width * height * 4) if you use the code above. Or even better: reuse the same vector instance, so that you don't allocate/free memory every time.
Laurent Gomila - SFML developer

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: update texture from a sf::image
« Reply #3 on: April 21, 2016, 10:38:37 pm »
What exactly are you doing with the sf::Image? Do you really have to go the slow way via sf::Image? Can't it be done with an sf::RenderTexture or a shader?

So as per the below thread, I have a map of europe where each region has a unique RGB value. That way when a user click on a pixel, I can check the colour of the SF::Image to determine exactly which region he has clicked on.

http://en.sfml-dev.org/forums/index.php?topic=19942.msg143704#msg143704

Now what I am also trying to add, is that when a user clicks on a region, the pixels that the user clicked on and the neighbouring regions pixels are all highlighted. (The idea being to show the user what regions he/she can move their army).

So I use the setImagePixelColour method that I put in my first post to do that - I'm unsure if there are faster ways to achieve the same effect? I have zero experience of shaders so I've honestly no idea if this can be
done via a shader - sorry.

As side note: Use references and not pointers to pass around objects (see my code above).

Oh ok, sry I'm going to go off tangent a little but is there is a reason? Sorry I am still new to programming in general so learning as I go. I googled and found some interesting answers but is there a reason specific to SFML that I should know about?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: update texture from a sf::image
« Reply #4 on: April 21, 2016, 10:57:38 pm »
So I use the setImagePixelColour method that I put in my first post to do that - I'm unsure if there are faster ways to achieve the same effect?
I have never written such a shader, but I'd claim that this would be the easiest to implement with it. You'd tell it what color should be changed and the mouse position and it should be able to replace the specific color.

Another and way more complicated solution I could think of is by keep using the sf::Image to check the position and collision, but for the rendering, you could revert again to the cutout countries and render them with different sprites, that way all you'd need to do is set the color of the sprite and it would change the country color.
But I think investing the time into learning something about GLSL shaders is the better way to go.

Oh ok, sry I'm going to go off tangent a little but is there is a reason? Sorry I am still new to programming in general so learning as I go. I googled and found some interesting answers but is there a reason specific to SFML that I should know about?
Nothing SFML specific. The main point is, that you can be certain that the reference will always contain a proper oject, while a pointer could potentially also hold a nullptr. Additionally you will get a nicer syntax, since you can  work with the . operator instead of the -> operator.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/