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

Author Topic: sf::Transformable::getTransform() broken?  (Read 2720 times)

0 Members and 2 Guests are viewing this topic.

dm

  • Newbie
  • *
  • Posts: 5
    • View Profile
sf::Transformable::getTransform() broken?
« on: November 06, 2014, 12:56:46 pm »
Consider this:
int main(int, char const**)
{
    sf::RenderWindow window(sf::VideoMode(480, 320), "SFML window");
   
    sf::RectangleShape parent;
    parent.setSize({50, 50});
    parent.setFillColor(sf::Color::Green);
    parent.setOrigin({-50, -50});
   
    sf::RectangleShape child;
    child.setSize({50, 50});
    child.setFillColor(sf::Color::Red);
   
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        window.clear();
        window.draw(parent);
        // child should be drawn at origin, but instead it drawn over parent.
        window.draw(child, parent.getTransform());
        window.display();
    }
    return EXIT_SUCCESS;
}
 

I think, child should be drawn at parent origin but instead it drawn over parent. It is a bug in getTransform() or I misunderstood something?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: sf::Transformable::getTransform() broken?
« Reply #1 on: November 06, 2014, 01:32:08 pm »
No, everything works as expected. The transformation gets applied to the child. It doesn't mean that the child gets placed at the parents origin.

In other words: The parent is created a position 0,0 with origin 0,0 and size 50,50. Then you set the origin to -50,-50. Now you apply the same transformation to the child object, which is created at position 0,0 with origin 0,0 and size 50,50 and the applied transformation set the origin to -50,-50, thus it's exactly at the same spot as parent.

Or in yet again other words: sf::Transform is essentially a 3x3 transformation matrix. If you know a bit vector math you'll understand that if the transformation matrix doesn't change and you pass in the same vector, you'll end up with the same result.

Parent(0, 0) => [ Transformation ] => Parent_T(50, 50)
Child(0, 0)  => [     Matrix     ] => Child_T(50, 50)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

dm

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: sf::Transformable::getTransform() broken?
« Reply #2 on: November 06, 2014, 02:03:27 pm »
But this is incorrect interpretation of parent-child relationship!
As an example, same parent-child in SpriteKit:
SKSpriteNode *parent = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(50, 50)];
[parent setAnchorPoint:CGPointMake(-1, -1)]; // same as {-50, -50} in SFML
[self addChild:parent];
   
SKSpriteNode *child = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
[child setAnchorPoint:CGPointMake(0, 0)]; // set to {0, 0} because default anchor is {0.5, 0.5}
[parent addChild:child];
 

See attached screenshot: child correctly positioned at parent origin.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: sf::Transformable::getTransform() broken?
« Reply #3 on: November 06, 2014, 02:52:41 pm »
Well I can only say again, you're assumptions/expectations are wrong. I explained how SFML works and that sf::Transform is a simple 3x3 transformation matrix and that passing it via render states simply multiplies the different transformation matrices. If you want to believe that it does something else, you can "believe" that, but it won't change the correctly working behavior. ;D

tl;dr you need to write code on your own to get a parent/child relationship working. You can take a look at the source code of the SFML Game Development book, which uses a node system with relative positioning.
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: sf::Transformable::getTransform() broken?
« Reply #4 on: November 06, 2014, 07:28:59 pm »
Quote
I think, child should be drawn at parent origin but instead it drawn over parent.
What do you think the difference is? If child is drawn at parent origin, and parent is obviously drawn at its own origin, then they both have the same origin and thus they end up one on top of the other. I don't know what else you would expect.
Laurent Gomila - SFML developer

dm

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: sf::Transformable::getTransform() broken?
« Reply #5 on: November 06, 2014, 07:44:43 pm »
What the "parent origin" is?
This is its top-left corner or m_origin?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
AW: sf::Transformable::getTransform() broken?
« Reply #6 on: November 06, 2014, 07:51:35 pm »
m_origin
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

dm

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: sf::Transformable::getTransform() broken?
« Reply #7 on: November 06, 2014, 08:08:26 pm »
Ok. Then why child drawn over parent? parent global top-left is (50, 50), global coords of "parent origin" m_origin = (0, 0).

What i trying to explain is exact behaviour of SpriteKit. I try understood why SFML and SpriteKit behaves so differently.
(btw, cocos2d behaves like SFML)
« Last Edit: November 06, 2014, 08:13:43 pm by dm »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: sf::Transformable::getTransform() broken?
« Reply #8 on: November 06, 2014, 08:39:51 pm »
A entity's origin, position, rotation and scale are combined into its transform (sf::Transform). So the transform and the set of individual transformations are equivalent.

Now back to your example. The parent has a modified origin of (-50, -50). The child has the default origin of (0, 0). But since you draw the child with the parent's transform, it inherits the origin of (-50, -50). So both child and parent end up being draw with the same origin. And since all their other attributes are the same (position, rotation, scale), they are exactly one on top of the other.

If you prefer another point of view, here it is. The parent's transform represents its origin (since all its other attributes are left to their default value). At draw time, it is not combined with another transform, so the parent's transform is all that is used for drawing the shape. The child transform is the identity, since all its attributes are left to their default value. But at draw time, it is combined with the parent's transform. So, again, the parent's transform is all that is used to draw the child shape. They are drawn with the exact same combined transform.

SpriteKit behaves differently because it is a little higher level: it implements explicit parent-child relationships, which causes implicit transformations to happen under the hood. SFML doesn't implement such a relationship between entities, all that happens with the transforms is what you explicitly do; nothing more nothing less.

It's you who calls these entites "parent" and "child", but they are just two separate entities drawn with the same transform.
« Last Edit: November 06, 2014, 08:44:28 pm by Laurent »
Laurent Gomila - SFML developer

dm

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: sf::Transformable::getTransform() broken?
« Reply #9 on: November 06, 2014, 09:09:10 pm »
Many thanks, that last post is very helpful.

 

anything