SFML community forums

Help => Graphics => Topic started by: JonnyLaw on January 13, 2021, 04:44:04 am

Title: creating a texture through code
Post by: JonnyLaw on January 13, 2021, 04:44:04 am
is there a way to create a blank texture with a set size, then access the pixels in the texture to set them?

something similar to the fallowing. (I specifically need the texture to be a pointer)

sf::Texture* texture;
texture = new sf::Texture;
texture->setSize(100, 100);

for (int y = 0; y < 100; y++)
{
    for (int x = 0; x < 100; x++)
    {
        texture->setPixel(sf::Color(127, 127, 127);
    }
}
Title: Re: creating a texture through code
Post by: Laurent on January 13, 2021, 09:17:37 am
No, SFML doesn't allow direct access to the texture pixels. A better solution is to work on a local pixel buffer, stored in system RAM, and then update the entire texture in a single call with the Texture::update function.
Title: Re: creating a texture through code
Post by: jacmoe on January 13, 2021, 02:16:49 pm
sf::Image is in many ways just a pixel buffer, so use that to update the texture as Laurent says.

A sf::Texture is just a sf::Image that lives on the graphics card.
Title: Re: creating a texture through code
Post by: Laurent on January 13, 2021, 04:06:44 pm
Quote
sf::Image is in many ways just a pixel buffer, so use that to update the texture as Laurent says.
If the texture is filled in real-time (ie. every frame), that's not what we advise, as pixel access in sf::Image is quite unoptimized. A raw array of sf::Uint8 is preferred in this case.
Title: Re: creating a texture through code
Post by: JonnyLaw on January 14, 2021, 07:41:16 am
how would i work on a local pixel buffer? would you be able to give a short code example of it? thanks for the reply
Title: Re: creating a texture through code
Post by: Laurent on January 14, 2021, 07:49:38 am
std::vector<sf::Uint8> image(width * height * 4);

// set pixel (x, y):
image[(x + y * width) * 4 + 0] = color.r;
image[(x + y * width) * 4 + 1] = color.g;
image[(x + y * width) * 4 + 2] = color.b;
image[(x + y * width) * 4 + 3] = color.a;

// update texture:
texture.update(image.data());
Title: Re: creating a texture through code
Post by: r4gTime on January 14, 2021, 12:18:22 pm
Thanks for your reply, Laurent.

I'm trying yo optimize fps in my game and realized my entire minimap took more than 16300 microseconds to draw with this code :
void Application::DrawMiniMap(){
    sf::RectangleShape rs;
    for(int i = 0; i < 100; i++) {
        for(int j = 0; j < 100; j++) {
                    rs.setPosition(2 * i, 2 * j);
                    rs.setSize(sf::Vector2f(2,2));
                    rs.setFillColor(img.tuile[game.carte.terrainType[i][j]].GetColor());
                    window.draw(rs);
        }
    }
}

I tried this code and it only takes about 300 microseconds now, but.. it doesn't work  ;D
void Application::DrawMiniMap(){

    sf::Texture tx;
    tx.create(100,100);
    std::vector<sf::Uint8> image(100 * 100 * 4);

    for(int x = 0; x < 100; x++) {
        for(int y = 0; y < 100; y++) {
            image[(x + y * 100) * 4 + 0] = img.tuile[game.carte.terrainType[x][y]].GetColor().r;
            image[(x + y * 100) * 4 + 1] = img.tuile[game.carte.terrainType[x][y]].GetColor().g;
            image[(x + y * 100) * 4 + 2] = img.tuile[game.carte.terrainType[x][y]].GetColor().b;
            image[(x + y * 100) * 4 + 3] = img.tuile[game.carte.terrainType[x][y]].GetColor().a;
        }
    }

    // update texture:
    tx.update(image.data());
    sf::Sprite spt;
    spt.setPosition(576,24);
    spt.setTexture(tx);
    window.draw(spt);
}

EDIT : I forgot to texture.create() and now it perfectly works with only ~350 microseconds, thanks a lot Laurent :)

EDIT 2: As my minimap is 200x200 and not 100, it actually takes 1250 microseconds to draw the minimap this way. Do you know a way to optimize even more ?
Title: Re: creating a texture through code
Post by: jacmoe on January 14, 2021, 01:12:03 pm
Does your map change each frame? Then you probably should create an sf::Image from the pixels and dump it to disk. You can then draw player and other things in a separate pixel array each frame and overlay it on top of the minimap.
Or at least move the map drawing code into a startup function so that it doesn't run each frame :)
Title: Re: creating a texture through code
Post by: Laurent on January 14, 2021, 01:29:25 pm
Indeed, all that stuff seems to be static, there's really no need to do it every frame. Even if the map was changing dynamically, you could make it much more efficient by creating the texture and allocating the pixel buffer once at init.
Title: Re: creating a texture through code
Post by: r4gTime on January 14, 2021, 02:31:52 pm
Indeed...

Thanks for your help jacmoe !