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

Author Topic: Transforming Individual Quad/Sprite in Vertex Array  (Read 2556 times)

0 Members and 1 Guest are viewing this topic.

YesBox

  • Newbie
  • *
  • Posts: 11
    • View Profile
Transforming Individual Quad/Sprite in Vertex Array
« on: May 30, 2022, 04:44:24 pm »
Hello, is there an official way to rotate/mirror an individual quad/sprite in a vertex array? All the documentation I've seen so far is for applying a transform to an entire vertex array.


eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Transforming Individual Quad/Sprite in Vertex Array
« Reply #1 on: June 01, 2022, 08:26:14 am »
Transforming the entire vertex array has a dedicated API and is often what you want, thus you see it more.

Transforming a single quad is just doing math on those four vertices.
You can use a standalone sf::Transform to help you with the transformation matrix and then call transformPoint for every vertex: https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Transform.php#ab42a0bb7a252c6d221004f6372ce5fdc
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

YesBox

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Transforming Individual Quad/Sprite in Vertex Array
« Reply #2 on: June 01, 2022, 05:59:37 pm »
I can't figure out how to implement what you're describing. I tried creating a sf::Transform, set the rotation to 90, and then apply that to each point in the quad. Doesn't work.

Here is my code that works, but is a hacky way to accomplish what I need. Note that gameMapPassed is a container with tiles to update in the game, and gameMap_ is a container that contains all game world tiles.


//...
finder = textureMap_.at( TileType::TILE_ATLAS_VARIANT ).getSize().x / TILE_SIZE;
//...

for( const auto& tile : gameMapPassed ) {
        int index = tile.first;

        sf::Vertex* quad = &vtexMap_.at( VertexLevel::USER_TILE )[gameMap_.at( index ).mutableTile.tile_id * 4];
        TileType tileType = tile.second.staticTile->type;
        int tileNumber = static_cast<int>( tileType );

        int x = index % mapWidth_;
        int y = index / mapWidth_;
        int tx = tileNumber % finder;
        int ty = tileNumber / finder;
       
        int rotation = tile.second.mutableTile.rotation;
        int rotaHelp {};

        switch( rotation ) {
                case 0: rotaHelp = 0; break;
                case 90: rotaHelp = 1; break;
                case 180: rotaHelp = 2; break;
                case 270: rotaHelp = 3; break;
        }

        quad[0].position = sf::Vector2f( x * TILE_SIZE, y * TILE_SIZE );                               
        quad[1].position = sf::Vector2f( ( x + 1 ) * TILE_SIZE, y * TILE_SIZE );
        quad[2].position = sf::Vector2f( ( x + 1 ) * TILE_SIZE, ( y + 1 ) * TILE_SIZE );
        quad[3].position = sf::Vector2f( x * TILE_SIZE, ( y + 1 ) * TILE_SIZE );

        if( tile.second.mutableTile.mirror == false ) {
                quad[( 0 + rotaHelp ) % 4].texCoords = sf::Vector2f( tx * TILE_SIZE, ty * TILE_SIZE ); 
                quad[( 1 + rotaHelp ) % 4].texCoords = sf::Vector2f( ( tx + 1 ) * TILE_SIZE, ty * TILE_SIZE );
                quad[( 2 + rotaHelp ) % 4].texCoords = sf::Vector2f( ( tx + 1 ) * TILE_SIZE, ( ty + 1 ) * TILE_SIZE );
                quad[( 3 + rotaHelp ) % 4].texCoords = sf::Vector2f( tx * TILE_SIZE, ( ty + 1 ) * TILE_SIZE );
        }
        else { 
                quad[( 1 + rotaHelp ) % 4].texCoords = sf::Vector2f( tx * TILE_SIZE, ty * TILE_SIZE );
                quad[( 0 + rotaHelp ) % 4].texCoords = sf::Vector2f( ( tx + 1 ) * TILE_SIZE, ty * TILE_SIZE );
                quad[( 3 + rotaHelp ) % 4].texCoords = sf::Vector2f( ( tx + 1 ) * TILE_SIZE, ( ty + 1 ) * TILE_SIZE );
                quad[( 2 + rotaHelp ) % 4].texCoords = sf::Vector2f( tx * TILE_SIZE, ( ty + 1 ) * TILE_SIZE );
        }
}
 

Essentially, by changing the order when filling out the quad[], you can rotate and/or mirror and individual tiles in the game. (e.g. 0 + rotaHelp could start at quad[2]. Then % 4 ensures the value wraps around to 0.).

It's long winded to describe why the rotation logic works. Im less certain why the mirror logic works, but it does. I discovered it by playing around with the ordeing some more.
« Last Edit: June 01, 2022, 06:02:14 pm by YesBox »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Transforming Individual Quad/Sprite in Vertex Array
« Reply #3 on: June 11, 2022, 05:13:29 pm »
I can't figure out how to implement what you're describing. I tried creating a sf::Transform, set the rotation to 90, and then apply that to each point in the quad. Doesn't work.

It's worth noting that any rotation will rotate around its (0, 0) (local) so I presume that's what you mean by "doesn't work."

Try negatively translating each point by the position you with to place the origin of the rotation, performing the rotation and then positively translating the point back.
NOTE: this will all be local co-ordinates.
FYI (in the unlikely situation you didn't know): in this case, translating a point effectively means change its position i.e. move it.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

AnhBao

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Transforming Individual Quad/Sprite in Vertex Array
« Reply #4 on: June 26, 2022, 03:11:20 pm »
You can use rotation matrix, something like:
    float alpha = 3.14f/2, sine = std::sin(alpha), cosine = std::cos(alpha);
    sf::Vector2f offset{(v[0].position + v[4].position)/2.f};
    for(int i = 0; i < 4; ++ i)
    {
        sf::Vector2f pos = v[i].position - offset;
        v[i].position = sf::Vector2f{pos.x*cosine - pos.y*sine, pos.x*sine + pos.y*cosine} + offset;
    }
This code rotates a quad including 4 vertex 90 degrees clockwise.