SFML community forums

General => General discussions => Topic started by: Laurent on August 06, 2011, 11:30:53 pm

Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 06, 2011, 11:30:53 pm
Hi :)

I've finally managed to work on the old task of splitting sf::Image into two separate classes: sf::Image (with less features) and a new sf::Texture class.

Here is a list of modifications, and I let you read the doc for more detailed information:
- sf::Texture replaces sf::Image almost everywhere (sf::Image is now used only for pixels manipulation, not for drawing)
- sf::Sprite now takes a sf::Texture (Set/GetImage are now Set/GetTexture)
- There's no more sf::Sprite::GetPixel (see below)
- sf::RenderImage is not sf::RenderTexture
- sf::RenderWindow::Capture is back
- I also added sf::Image::FlipHorizontally and FlipVertically

The only drawback of this modification is that you can't retrieve pixels from a texture, and thus from a sprite, anymore. For pixel-perfect collision detection you must now store the collision data yourself (which allows more optimizations, by the way).

I've probably forgotten a few things, so don't hesitate to ask question :)
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 06, 2011, 11:44:48 pm
Cool! I like that you created shortcuts for direct loading from sf::Texture :)

What does void Texture::Update(const Window&  window) exactly do? The documentation says "Update the texture from the contents of a window" which is not really more information than I am given by the function signature ;)

If it performs a screenshot, what's the difference to Image RenderWindow::Capture() const? Only the indirection via sf::Image?
Title: sf::Texture implemented in SFML 2
Post by: Grimshaw on August 07, 2011, 12:03:32 am
Does it load the image anyway without regarding the GPU capacity like i've mentioned before? :)
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 07, 2011, 12:19:04 am
Another question, how do sf::Texture's methods void Update(const Image&) and bool LoadFromImage(const Image&) differ? The difference I have seen until now is that the former requires that the texture be created beforehand. Can't Update() fail? Maybe you should emphasize those points more explicitly in the documentation :)

And doesn't sf::Texture have a CreateMaskFromColor() anymore? Is it because the sf::Image doesn't really exist after loading, so this would have to be specified at texture creation time?
Title: sf::Texture implemented in SFML 2
Post by: Contadotempo on August 07, 2011, 12:33:58 am
If it's not possible to retrieve the pixel data from sf::texture, how can I store/make my own data for pixel-perfect collision?
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 07, 2011, 12:43:47 am
Contadotempo, I think you can load a sf::Image with the pixels. Then, you are able to create the sf::Texture from it, as well as to access its pixels for your algorithm.

Alternatively, you can store a more memory-efficient solution than sf::Image. After all, you probably only need 1 bit per pixel (solid or not) instead of 32. But you still need a sf::Image first.

Unfortunately, this leads to unnecessary, expensive copies. If sf::Texture::LoadFromImage() took a sf::Image copy instead of const-reference, you could use C++0x std::move() to pass the image as argument – given that the automatic generation of an sf::Image move constructor is possible (no big three defined).
Title: sf::Texture implemented in SFML 2
Post by: Xp on August 07, 2011, 05:25:12 am
is it me or i cannot compile this build? :roll:

LaurentGomila-SFML-b718464\include\SFML\Graphics\Font.hpp|243|error: declaration of 'sf::Texture sf::Font::Page::Texture'|

LaurentGomila-SFML-b718464\include\SFML\Graphics\Texture.hpp|48|error: changes meaning of 'Texture' from 'class sf::Texture'|


oh nevermind, changed Texture to sf::Texture in Font (243) and errors gone :twisted:
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 07, 2011, 10:07:42 am
Quote
What does void Texture::Update(const Window& window) exactly do? The documentation says "Update the texture from the contents of a window" which is not really more information than I am given by the function signature

It copies the current contents of the window to the texture. What else can I say? Maybe "copy" is more relevant than "update" in the comments?

Quote
If it performs a screenshot, what's the difference to Image RenderWindow::Capture() const? Only the indirection via sf::Image?

Texture and Image are two different things, therefore updating a texture and updating an image (from a window) are also two different things. Both are optimized, using one to implement the other would be very ineficient.
Finally, I'd say that:
- The main purpose of Texture::Update(Window&) is to implement real-time post-effects with shaders, everything stays on the GPU
- The main purpose of RenderWindow::Capture() is to take screenshots of the application, it downloads the pixels to the system memory

Quote
Does it load the image anyway without regarding the GPU capacity like i've mentioned before?

Are you talking about texture size or memory capacity? For the first one it returns an error, but for the second one it prints a warning in the error output.

Quote
Another question, how do sf::Texture's methods void Update(const Image&) and bool LoadFromImage(const Image&) differ? The difference I have seen until now is that the former requires that the texture be created beforehand. Can't Update() fail? Maybe you should emphasize those points more explicitly in the documentation

Update only copies pixels, it doesn't create anything nor perform any check. It's a fast function that can be used to stream contents to a texture in real-time, like a video.
LoadFromXxx create the texture.

Quote
Can't Update() fail?

It does nothing if the texture has not been created yet.
It crashes if one of the parameters is wrong (size doesn't match, etc.) -- it provides maximum performances so you are responsible for providing correct parameters.

Quote
And doesn't sf::Texture have a CreateMaskFromColor() anymore? Is it because the sf::Image doesn't really exist after loading, so this would have to be specified at texture creation time?

Absolutely. sf::Texture only knows how to upload and download pixels to the graphics card. If you have custom processing to apply to these pixels, you must do it before providing the pixels to sf::Texture.

Quote
Unfortunately, this leads to unnecessary, expensive copies

Where are those copies?

Quote
is it me or i cannot compile this build?

Oops, I'll fix this ASAP, sorry.
Title: sf::Texture implemented in SFML 2
Post by: pdinklag on August 07, 2011, 11:39:04 am
Nice stuff!
So simply put (application-wise), Texture replaces Image, and Image is needed only if you need to do pixel manipulation.

A minor thing I noticed, Image.hpp still includes Resource.hpp, that one seems to be obsolete now.
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 07, 2011, 12:57:08 pm
Thanks for the explanations.

Quote from: "Laurent"
It copies the current contents of the window to the texture. What else can I say? Maybe "copy" is more relevant than "update" in the comments?
Maybe... But I was confused since most of the functionality of the old sf::Image was moved to sf::Texture. I also expected this to be the case for the screenshots, not thinking that sf::Texture wraps a pure OpenGL texture ;)

As far as I understand it, the sf::Texture::Update() overloads are rather an advanced feature, and one only needs them for low-level modification of the underlying OpenGL texture.

Quote from: "Laurent"
- The main purpose of RenderWindow::Capture() is to take screenshots of the application, it downloads the pixels to the system memory
Okay. By the way, why did you move this functionality to sf::RenderWindow again? If you leave it like this, you should maybe declare a single sf::Image in the implementation of Capture() and always return it. Some compilers disable NRVO (Named Return Value Optimization) if different objects are returned, leading to additional slow copies.

With a function void Image::CopyScreen(const RenderWindow& window) however, you could avoid this copy without relying on optimizations. Apart from that, a void Image::CopyTexture(const Texture& texture) could be used instead of Image Texture::CopyToImage() const, so this would be handled in a centralized and uniform way. Or create Copy() overloads. Plus, you can later add error checking (bool return value). But maybe the implementation can't be located inside the sf::Image class, and you don't consider friend-outsourcing appropriate either...

Quote
Update only copies pixels, it doesn't create anything nor perform any check. [...]
LoadFromXxx create the texture.
So LoadFromXY() is basically a Create() followed by Update()?

Quote from: "Laurent"
Where are those copies?
Ah, they are nowhere :)

Sorry, I first thought sf::Texture::LoadFromImage() would store a copy of the image, but in fact it directly initializes the OpenGL texture. There is just one temporary sf::Image, but that cannot be avoided anyway.
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 07, 2011, 01:47:59 pm
Quote
So simply put (application-wise), Texture replaces Image, and Image is needed only if you need to do pixel manipulation.

Absolutely.

Quote
A minor thing I noticed, Image.hpp still includes Resource.hpp, that one seems to be obsolete now.

Thanks :)

Quote
As far as I understand it, the sf::Texture::Update() overloads are rather an advanced feature, and one only needs them for low-level modification of the underlying OpenGL texture.

Correct.

Quote
Okay. By the way, why did you move this functionality to sf::RenderWindow again?

Previously the Texture::Update(Window) and RenderWindow::Capture() features were merged. That's why it was available as Image::CopyScreen(Window&).
But now that its only purpose is to take screenshots, I went back to the most convenient interface.

Quote
Apart from that, a void Image::CopyTexture(const Texture& texture) could be used instead of Image Texture::CopyToImage() const, so this would be handled in a centralized and uniform way. Or create Copy() overloads.

I didn't want sf::Image to know about sf::Texture. It's purely a design decision ;)
In my opinion, CopyToImage is a single-shot operation, I can't think of a use case that would require updating the same image again and again from a texture.

Quote
So LoadFromXY() is basically a Create() followed by Update()?

This is exactly how they are implemented :)
Title: sf::Texture implemented in SFML 2
Post by: Contadotempo on August 07, 2011, 04:18:22 pm
Think I understand these more clearly now.
Kind of panicked a little because I was actually working on a pixel-perfect collision algorithm when this commit came out and I thought I would need to change a bunch of code, but turns out nothing much changed I guess.

Thank you.
Title: sf::Texture implemented in SFML 2
Post by: OniLinkPlus on August 07, 2011, 10:54:38 pm
Quote from: "Laurent"
I didn't want sf::Image to know about sf::Texture. It's purely a design decision ;)
So sf::Image developed split personality disorder and doesn't realize it?
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 17, 2011, 12:13:02 pm
Why does it have to come when I'm busy? Anyway great change and I'll get right on getting it into rbSFML. Got really interested on creating images bigger than max texture size. Should be possible with this change.
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 17, 2011, 12:22:00 pm
Quote
Got really interested on creating images bigger than max texture size. Should be possible with this change.

Indeed it is.
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 18, 2011, 10:47:27 pm
Quote from: "Laurent"
In my opinion, CopyToImage is a single-shot operation, I can't think of a use case that would require updating the same image again and again from a texture.


Well I totally agree with this but I can't help feeling that for rbSFML this will be really bad and slow cause it means that it will create a copy from the return value of the CopyToImage function and then a copy again from that object to a heap-based object so it can be used in the bindings. Or am I missing something I can do here to remove that second copy?

Still sure it should not be part of the normal frame iteration of a game but this means that this is double as slow just because. I'm not obsessed with optimizing code(Haven't tried optimizing rbSFML at all, will do that when sfml2 is done) but it nags me back in my head when it can be avoided.

The code will be something like:
Code: [Select]

static VALUE Texture_CopyToImage( VALUE self )
{
    // Code code code
    VALUE newImage = // Allocate a new Ruby image.
    sf::Image *imagePtr = NULL;
    Data_Get_Struct( newImage, sf::Image, imagePtr );
    *imagePtr = selfPtr->CopyToImage();
    return newImage;
}


But I guess if I can manage to do something like this the second copy won't be made?
Code: [Select]

sf::Image *newImage = new sf::Image( texture->CopyToImage() );


Or does it not matter?
Title: Re: sf::Texture implemented in SFML 2
Post by: Haikarainen on August 19, 2011, 07:33:56 am
Quote from: "Laurent"
The only drawback of this modification is that you can't retrieve pixels from a texture, and thus from a sprite, anymore. For pixel-perfect collision detection you must now store the collision data yourself (which allows more optimizations, by the way).


Why was this needed? This breaks ALOT of stuff for me :/ also my project has been on ice in waiting for SFML2 Release, and now this? WHY? :( youre breaking my heart......



...
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 19, 2011, 11:10:53 am
Because of such changes, it is usually recommandable to couple graphics (sf::Image/sf::Texture) and game logics (collision) not too tightly. I know this is difficult for pixel-perfect collision, but now you need an abstraction layer anyway – unless you want to waste a lot of memory with sf::Image.
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 19, 2011, 11:21:19 am
Quote
Well I totally agree with this but I can't help feeling that for rbSFML this will be really bad and slow cause it means that it will create a copy from the return value of the CopyToImage function and then a copy again from that object to a heap-based object so it can be used in the bindings. Or am I missing something I can do here to remove that second copy?

How is this different from the direct use in C++?
Code: [Select]
sf::Image image;
image = texture.CopyToImage();
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 19, 2011, 12:08:54 pm
I don't know. Probably is. Just that I have to do it in more steps that fools me. Also I'm writing everything from my phone so hard to see the big picture. Coding like this is difficult but fun.
Title: sf::Texture implemented in SFML 2
Post by: Haikarainen on August 19, 2011, 03:36:11 pm
Is there ANY possibility to get pixel information from a texture?
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 19, 2011, 04:35:42 pm
Quote from: "Haikarainen"
Is there ANY possibility to get pixel information from a texture?


Yeah by converting it to a image.
Title: sf::Texture implemented in SFML 2
Post by: bastien on August 19, 2011, 05:19:58 pm
This may be a stupid question, but does create() recreate the texture if it was already created? Is it the right way to change the texture's dimensions?
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 19, 2011, 05:35:22 pm
Quote
Is it the right way to change the texture's dimensions?

Yes, but then its contents will be uninitialized, you'll have to update it with valid pixels.
Title: sf::Texture implemented in SFML 2
Post by: bastien on August 19, 2011, 06:47:15 pm
I just saw that you renamed Image::LoadFromPixels() to Create(). Why?
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 19, 2011, 06:55:02 pm
"Create" functions are more basic than "Load" functions, and they can't fail (they return void). This is my logic, I don't know if it makes sense or not :lol:
Title: sf::Texture implemented in SFML 2
Post by: prchakal on August 19, 2011, 11:41:28 pm
Hi,

How to get pixels now?

Before this mod we can use GetPixel from sprite, and now?
Title: sf::Texture implemented in SFML 2
Post by: Nexus on August 20, 2011, 02:53:23 am
Quote from: "prchakal"
How to get pixels now?

Before this mod we can use GetPixel from sprite, and now?
Wasn't that anwered by Groogy?

You can use sf::Texture::CopyToImage() to get the corresponding pixel container sf::Image.
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 21, 2011, 02:21:26 pm
Think this part in the documentation is wrong: http://sfml-dev.org/documentation/2.0/classsf_1_1Image.php#a95667a08de2ec1b06fae4a9784eea669

Quote
Load the image from a custom stream.

The supported image formats are bmp, png, tga, jpg, gif, psd, hdr and pic. Some format options are not supported, like progressive jpeg. The maximum size for an image depends on the graphics driver and can be retrieve with the GetMaximumSize function. If this function fails, the image is left unchanged.


Image isn't bound by the maximum size of the graphics driver right?

ALSO! I freakin hate you for the array of Update methods.... Ruby doesn't let you have the same method name with different argument lists in an easy way so I have to fake it using variable argument lists. 2 or 3 different are hard and worrying but this is just insane! Note: This is not a request for you to change it or else I will have done all this work for nothing :P
Title: sf::Texture implemented in SFML 2
Post by: Laurent on August 21, 2011, 09:13:55 pm
Quote
Think this part in the documentation is wrong

Yup, it's fixed now.

Quote
ALSO! I freakin hate you for the array of Update methods.... Ruby doesn't let you have the same method name with different argument lists in an easy way so I have to fake it using variable argument lists

Well, do it the way you prefer, you're not forced to use the same name for all the overloads. CSFML uses three functions: UpdateFromPixels, UpdateFromImage and UpdateFromWindow.
Title: sf::Texture implemented in SFML 2
Post by: Groogy on August 21, 2011, 10:31:49 pm
Quote from: "Laurent"
Well, do it the way you prefer, you're not forced to use the same name for all the overloads. CSFML uses three functions: UpdateFromPixels, UpdateFromImage and UpdateFromWindow.


Well since I don't have any online reference for rbSFML and the documentation is easily out of date I try to keep it as close to C++ SFML as possible so you can use your online documentation. I even break the Ruby code standard(but still support it) so that you can use the same symbols as you could in C++ so it's easy to get started. I feel making it easier to use is way more important than making it easier for me to develop it.

So you could say that this is the way I prefer it just that I got unlucky with having so many overloaded methods. :wink:

Anyway it was not as hard to do as I made it sound just that the code became a little ugly and obscure for my taste. I like it when you can read the code straight of and immediately get a grip of what's going on.
Title: sf::Texture implemented in SFML 2
Post by: Tank on August 22, 2011, 09:37:51 am
Great addition to SFML2. Breaks my 10K+ source lines of code project at a lot of places, but also enhances the usage. Thanks :)
Title: Re: sf::Texture implemented in SFML 2
Post by: SinisterRainbow on August 29, 2011, 06:45:52 pm
Quote from: "Haikarainen"
Quote from: "Laurent"
The only drawback of this modification is that you can't retrieve pixels from a texture, and thus from a sprite, anymore. For pixel-perfect collision detection you must now store the collision data yourself (which allows more optimizations, by the way).


Why was this needed? This breaks ALOT of stuff for me :/ also my project has been on ice in waiting for SFML2 Release, and now this? WHY? :( youre breaking my heart......



...


What about tile-based games (think legend of zelda/shining force)? If you have a texture loaded into video memory with all tiles (like: dirt, grass, stone, entrance). Wouldn't a texture.Copy(texture, coordinates,intrect) be the fastest way to go about this?

Also, it seems like it would be compatible with earlier versions - and give users greater freedom in their coding.
Title: Re: sf::Texture implemented in SFML 2
Post by: Haikarainen on August 30, 2011, 08:57:30 am
Quote from: "SinisterRainbow"
Quote from: "Haikarainen"

Why was this needed? This breaks ALOT of stuff for me :/ also my project has been on ice in waiting for SFML2 Release, and now this? WHY? :( youre breaking my heart......



...


What about tile-based games (think legend of zelda/shining force)? If you have a texture loaded into video memory with all tiles (like: dirt, grass, stone, entrance). Wouldn't a texture.Copy(texture, coordinates,intrect) be the fastest way to go about this?

Also, it seems like it would be compatible with earlier versions - and give users greater freedom in their coding.


Lol, i was really tired and cranky when i wrote that :P Been thinking about it and i really like this change! Will create  2darrays of bools to generate collisionmaps at resourceloading, this will give me way more freedom and also speed up gameplay and performance significantly!
Title: sf::Texture implemented in SFML 2
Post by: vidjogamer on January 18, 2012, 03:55:44 pm
Is this supposed to cause the speakers to repeatedly beep?
Also it crashes and the file is in the application directory.

Code: [Select]

sf::Texture texture;
texture.LoadFromFile("green_128.png");
Title: sf::Texture implemented in SFML 2
Post by: Laurent on January 18, 2012, 04:23:42 pm
Quote
Is this supposed to cause the speakers to repeatedly beep?
Also it crashes and the file is in the application directory.

Of course not... so please open a new thread and give all the required details.
http://www.sfml-dev.org/forum/viewtopic.php?t=5559
Title: sf::Texture implemented in SFML 2
Post by: vidjogamer on January 24, 2012, 05:52:58 am
Sorry. I actually deleted that test project. The code was really that simple though. Just initialization and a sound played on the LoadFromFile() line.

I believe that the strange behavior was a result of linking the libs wrong. Maybe linking to release from a debug build. That solved some other strange issues I had in another project, but I have not tested it here.

You would probably know more than I if that could cause such a problem?