SFML community forums

General => Feature requests => Topic started by: superjoe on August 06, 2014, 04:43:49 pm

Title: ability to use rotated images with setTextureRect
Post by: superjoe on August 06, 2014, 04:43:49 pm
Some texture packers rotate images 90 degrees clockwise or counter-clockwise for efficient packing. When loading textures, the OpenGL code would look something like this:

GLfloat coords[4][2];
if (info->r90) {
    coords[0][0] = (info->x + info->width) / textureWidth;
    coords[0][1] = info->y / textureHeight;

    coords[1][0] = info->x / textureWidth;
    coords[1][1] = info->y / textureHeight;

    coords[2][0] = (info->x + info->width) / textureWidth;
    coords[2][1] = (info->y + info->height) / textureHeight;

    coords[3][0] = info->x / textureWidth;
    coords[3][1] = (info->y + info->height) / textureHeight;
} else {
    coords[0][0] = info->x / textureWidth;
    coords[0][1] = info->y / textureHeight;

    coords[1][0] = info->x / textureWidth;
    coords[1][1] = (info->y + info->height) / textureHeight;

    coords[2][0] = (info->x + info->width) / textureWidth;
    coords[2][1] = info->y / textureHeight;

    coords[3][0] = (info->x + info->width) / textureWidth;
    coords[3][1] = (info->y + info->height) / textureHeight;
}
glBindBuffer(GL_ARRAY_BUFFER, info->texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), coords, GL_STATIC_DRAW);
glEnableVertexAttribArray(spritesheet.attribTexCoord);
glVertexAttribPointer(spritesheet.attribTexCoord, 2, GL_FLOAT, GL_FALSE, 0, NULL);

With SFML, I want to do something like this:

sf::Sprite sprite;
sprite.setTexture(spritesheet);
sprite.setTextureRect(sf::IntRect(info->x, info->y, info->width, info->height), info->r90 ? sf::Clockwise90 : sf::NoRotation);

So SFML would check the second parameter which might inform it to set slightly different UV coords taking into account this rotation.

Alternate API could be
sprite.setTextureRectRotation(sf::Clockwise90)
.

Another alternative would simply be making updateTexCoords public instead of private.

I looked into SFML's code and it looks very clean and understandable. I would be happy to implement this feature. What I want to know is, are you interested in this feature? Should I make a pull request?
Title: Re: ability to use rotated images with setTextureRect
Post by: Peteck on August 06, 2014, 04:54:22 pm
One could just make a rotation calculation on the coordinates or just get the new coordinates from the packed texture. In my opinion its better to use the right coordinates than start rotating them to get right ones. But of course, its not up to me to make that decision.
Title: Re: ability to use rotated images with setTextureRect
Post by: superjoe on August 06, 2014, 04:57:53 pm
One could just make a rotation calculation on the coordinates or just get the new coordinates from the packed texture. In my opinion its better to use the right coordinates than start rotating them to get right ones. But of course, its not up to me to make that decision.

I don't think I'm communicating clearly. Consider a spritesheet like this:

(http://i.imgur.com/HG5XUQf.png)

Note that it has images that are normal and also images that are rotated 90 degrees. This is to make the spritesheet more efficient.

So I'm not using "wrong" coordinates. I'm using efficient texture packing, and it's easy to read the image from the texture in the correct orientation by adjusting the UV coords.

SFML just needs to let me call updateTexCoords manually or provide an API that understands rotation.
Title: Re: ability to use rotated images with setTextureRect
Post by: Hapax on August 06, 2014, 05:29:42 pm
You want to access rotated images to provide unrotated textures? Seems like a reasonable and common thing to need.
I'm not sure I fully understood but were you saying that OpenGL already provides this feature but SFML blocks it?

I suppose it's always possible to unpack them and repack them (without rotation) for your project although this sounds cumbersome.
I also suppose you could use sf::Image and copy and rotate the parts that you need but that seems like unnecessary work.
 ???

The other option is of course to modify SFML source for yourself but that doesn't help anyone else...
Title: Re: ability to use rotated images with setTextureRect
Post by: superjoe on August 06, 2014, 05:57:14 pm
The other option is of course to modify SFML source for yourself but that doesn't help anyone else...

I'm happy to submit a patch. This feature would be straightforward to write and small. I only want the blessing of the project leader(s) that they agree with the feature.
Title: Re: ability to use rotated images with setTextureRect
Post by: Peteck on August 06, 2014, 05:59:01 pm
Hmm there are some problems by making this rotation function. First of all, what point should it rotate around? Lets say that it should just rotate around the center. If you then say the coordinates are like this

x: 0, y: 0, width: 50, height 25

When rotating this around the center you will get a wrong x coordinates outside the texture.
Title: Re: ability to use rotated images with setTextureRect
Post by: superjoe on August 06, 2014, 06:21:33 pm
Hmm there are some problems by making this rotation function. First of all, what point should it rotate around? Lets say that it should just rotate around the center. If you then say the coordinates are like this

x: 0, y: 0, width: 50, height 25

When rotating this around the center you will get a wrong x coordinates outside the texture.

There's no problem here. Don't think of it like a rotation point, think of it as simply storing the image sideways. It's just a matter of different UV coords. Example from SFML:

Before:


void Sprite::updateTexCoords()
{
    float left   = static_cast<float>(m_textureRect.left);
    float right  = left + m_textureRect.width;
    float top    = static_cast<float>(m_textureRect.top);
    float bottom = top + m_textureRect.height;

    m_vertices[0].texCoords = Vector2f(left, top);
    m_vertices[1].texCoords = Vector2f(left, bottom);
    m_vertices[2].texCoords = Vector2f(right, top);
    m_vertices[3].texCoords = Vector2f(right, bottom);
}

After:

void Sprite::updateTexCoords()
{
    float left   = static_cast<float>(m_textureRect.left);
    float right  = left + m_textureRect.width;
    float top    = static_cast<float>(m_textureRect.top);
    float bottom = top + m_textureRect.height;

    if (r90) {
      m_vertices[0].texCoords = Vector2f(right, top);
      m_vertices[1].texCoords = Vector2f(left, top);
      m_vertices[2].texCoords = Vector2f(right, bottom);
      m_vertices[3].texCoords = Vector2f(left, bottom);
    } else {
      m_vertices[0].texCoords = Vector2f(left, top);
      m_vertices[1].texCoords = Vector2f(left, bottom);
      m_vertices[2].texCoords = Vector2f(right, top);
      m_vertices[3].texCoords = Vector2f(right, bottom);
    }
}
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 06, 2014, 06:25:53 pm
Indeed, this feature would be easy to implement and your use case is relevant. Now we need to see whether we want it, and what API we would expose.

Personnally, I have no strong argument against it.

PS: your implementation is incomplete, the vertices' positions need to be adjusted as well.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 06, 2014, 06:48:18 pm
What speaks against providing a
setTextureRect(int left, int top, int right, int bottom);
overload in addition to the sf::IntRect one?

By breaking up the coordinates, we won't have to assume that the source texture rectangle always has the same orientation. Rotations could be expressed solely through manipulation of those coordinates. What's more: even mirroring along any axes could be expressed through manipulation of those coordinates and wouldn't force the user to rely on a non-trivial setScale() with a negative value which might even break other things.

The sf::Sprite would store those ints instead of the oriented sf::IntRect which doesn't even change it's size. This wouldn't break existing code either.
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 06, 2014, 06:50:37 pm
How can you specify a rotated rectangle with (left, top, right, bottom)? ???
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 06, 2014, 06:59:36 pm
Hmm yeah... I realized what I actually meant were points instead of single values :P.

setTextureRect(const sf::Vector2i& leftTop, const sf::Vector2i& rightTop, const sf::Vector2i& rightBottom, const sf::Vector2i& leftBottom);

This provides more flexibility than most people might need... being able even to skew images etc. for whatever reason there might be.
Title: Re: ability to use rotated images with setTextureRect
Post by: minirop on August 06, 2014, 07:01:26 pm
probably with having, let say, top/left being the top right corner and a negative width and let SFML do the work (for a 90 CW rotation) but probably too much hassle.
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 06, 2014, 07:12:42 pm
Quote
Hmm yeah... I realized what I actually meant were points instead of single values
Maybe this is too much? I think it would considerably complicate the implementation of other functions, as well as the overall API of the sf::Sprite class.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 06, 2014, 07:28:38 pm
I think it would considerably complicate the implementation of other functions
Not really... I just checked and there aren't that many places where the textureRect is actually accessed. Setting the textureRect and texture as well as bounds calculation.

as well as the overall API of the sf::Sprite class
This would only add 1 additional overload to the sf::Sprite class. getTextureRect would still return an oriented rectangle computed from the points.
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 06, 2014, 11:21:45 pm
A getTextureRect() function doesn't make sense anymore if we can give 4 arbitrary pairs of texture coordinates. We would have to return something similar to what we can set, i.e. the 4 pairs of texture coordinates. A simple texture rect can still be retrieved with getLocal/GlobalBounds().

And what about shapes? If we go this way, there's no reason to limit shape texturing to an AABB rectangle, we should be able to set each point's texture coordinates as well.

That's what I have in mind when I say that the API would be more complicated.

Now for the implementation... sf::Sprite's local geometry is directly deduced from the texture rectangle. What if now we can set any shape composed of 4 points? The sprite will no longer be a quad.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 07, 2014, 12:53:36 am
And what about shapes? If we go this way, there's no reason to limit shape texturing to an AABB rectangle, we should be able to set each point's texture coordinates as well.
Isn't this a good thing? We don't want to limit peoples' creativity just because we aren't as creative as them ;). This would also solve the "cookie cutter" problem where a texture might not be properly spanned across a polygon if it isn't a quad, since that is currently the assumption of shape texturing.

Now for the implementation... sf::Sprite's local geometry is directly deduced from the texture rectangle. What if now we can set any shape composed of 4 points? The sprite will no longer be a quad.
This is also a good thing to have. Imagine how happy all of the people making isometric tile games would be if they could have sprites that are rhombuses instead of quads. :D Tighter texture atlas packing, less overdraw (more GPU performance) and less headaches among many other things.
Title: Re: ability to use rotated images with setTextureRect
Post by: kimci86 on August 07, 2014, 12:31:32 pm
Hi,
In my humble opinion, this feature already exists with sf::VextexArray.
What do you think ? Are you against using it ?
Title: Re: ability to use rotated images with setTextureRect
Post by: thomas9459 on August 07, 2014, 06:23:56 pm
In my humble opinion, this feature already exists with sf::VextexArray.
What do you think ? Are you against using it ?
There are many cases where an sf::Sprite would be preferred because of the other functions provided by the class, especially the rotation/position/origin ones.
Title: Re: ability to use rotated images with setTextureRect
Post by: wintertime on August 08, 2014, 11:28:35 pm
Why is this needed so much when in the end the output from rotating the texture coordinates would look the same as rotating the sprite? Some adjustment to client code would always be needed when using such a weird rotating texture packer.
Title: Re: ability to use rotated images with setTextureRect
Post by: superjoe on August 09, 2014, 08:52:04 pm
Why is this needed so much when in the end the output from rotating the texture coordinates would look the same as rotating the sprite? Some adjustment to client code would always be needed when using such a weird rotating texture packer.

It's not weird. Many texture packers have this feature.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 09, 2014, 09:05:31 pm
I think the question is whether SFML should explicitly support rotating texture rectangles because of these packers, whether it should leave the image rotating to the user to do in their code (e.g. somewhere in a resource manager) or whether SFML should support generic texture source specifications like I proposed. I still feel like if we were to implement something that made texturing sprites more flexible, we should go all the way, for the reasons I already mentioned. Locking rotations to multiples of 90 degrees sounds too much like catering to a specific subset of packers. After all, there might be obscure packers that rotate sprites in angles that are not multiples of 90 degrees... what do we do then?
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 09, 2014, 10:47:48 pm
The good thing with rotated rectangles is that modifications to the public API are minimal, while providing a feature which can be useful in multiple areas.

The full flexibility of providing the 4 texture coordinates directly solves more obscur problems, makes the public API and implementation much more complicated, for something that can already be done easily with vertex arrays. Don't forget that sprites are just a higher-level abstraction, the class itself exists only to makes things simpler, it doesn't do anything that can't already be done with vertex arrays. Making it more complicated would make it quite useless.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 09, 2014, 11:34:08 pm
The most "annoying" thing about using an sf::VertexArray instead of a regular sf::Sprite is the fact that sf::VertexArray isn't derived from sf::Transformable like sf::Sprite is. Even if you mean to use it as a rigid body, which implies that all rigid body transformations are applicable to it as well, SFML doesn't allow you to do that. I can't tell how annoying this is to those who actually care because I don't make extensive use of it myself, but I can imagine that some people might be put off by the fact that they have to sacrifice the transformable interface just because their texture data doesn't fit perfectly to sf::Sprite's assumptions.
Title: Re: ability to use rotated images with setTextureRect
Post by: Laurent on August 10, 2014, 09:42:25 am
class MyFlexibleSprite : public sf::Drawable, public sf::Transformable
{
    ... vertex array ... texture coordinates ...
};
Title: Re: ability to use rotated images with setTextureRect
Post by: superjoe on August 10, 2014, 11:29:37 am
Locking rotations to multiples of 90 degrees sounds too much like catering to a specific subset of packers. After all, there might be obscure packers that rotate sprites in angles that are not multiples of 90 degrees... what do we do then?

I don't think this makes sense. Rotating 90 degrees you're guaranteed to be able to fit all the pixels in there perfectly and pretend that you never rotated the texture. Any other value and you give up 1:1 pixel mapping.
Title: Re: ability to use rotated images with setTextureRect
Post by: binary1248 on August 10, 2014, 11:09:20 pm
I guess if sf::Sprite were to be limited to usage with axis-aligned sprite sheets your code would be fine with me as well :).
Title: Re: ability to use rotated images with setTextureRect
Post by: Juhani on August 14, 2014, 03:09:36 pm
probably with having, let say, top/left being the top right corner and a negative width and let SFML do the work (for a 90 CW rotation) but probably too much hassle.

IMHO this is a good idea.

Edit: ;D Just realized that this would cause mirroring but not rotating. ::)

How about taking as arguments the top left and bottom right corner? If bottom right is more left than top left the texture is rotated 90 degrees, if higher it is -90 degrees, and if bottom right is both above and left of top left 180 degrees.