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

Author Topic: Textured shape - texture not rotate (SFML + Box2d)  (Read 2779 times)

0 Members and 1 Guest are viewing this topic.

kubawal

  • Newbie
  • *
  • Posts: 9
    • View Profile
Textured shape - texture not rotate (SFML + Box2d)
« on: February 15, 2014, 02:33:18 pm »
Hi!
I'm writing an offroad 2d game using Box2d and SFML. And i have got a problem with texturing objects - texture of the shape don't rotate with it ->
// B2toSF() and SFtoB2() convert units beetween pixels and Box2d
// RDtoDG() convert radians to degreeses
void Body::displayBody(RenderWindow &win, b2Body *b, const Texture** fillTexture)
// draws all fixtures in *b on win
// fillTexture is ptr to list of ptrs to textures to all fixtures, NULL is NO TEXTURING
{
    int i = 0;
    for(b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext(), i++)
    // for each fixtures in body
    {
         // shape and aabb of body - don't interest with it, it's box2d utility
        b2AABB aabb = f->GetAABB(0);
        b2Shape* sh = f->GetShape();
        RenderStates st; // transform for all shapes
       
        // rotate shape by center of its aabb
        st.transform.rotate(RDtoDG(b->GetAngle()), B2toSF(aabb.GetCenter()));

        switch(sh->GetType())
        {
        case b2Shape::e_polygon: // polygon shape
        {
            b2PolygonShape* s = dynamic_cast<b2PolygonShape*>(sh);
            ConvexShape cs(s->GetVertexCount());
            // shapes are NOT ROTATED, RenderStates::transform contains their rotation
            if(fillTexture[i])
                cs.setTexture(fillTexture[i]);
            else
                cs.setFillColor(Color::Red);
            for(int i = 0; i < s->GetVertexCount(); i++)
                cs.setPoint(i, B2toSF(b->GetWorldPoint(s->GetVertex(i))));
                // GetWorldPoint() translates local position to global coordinates
            win.draw(cs, st);
            break;
        }
        case b2Shape::e_circle: // circle
        {
            b2CircleShape* s = dynamic_cast<b2CircleShape*>(sh);
            CircleShape cs(B2toSF(s->m_radius));
            cs.setPosition(B2toSF(aabb.lowerBound)); // left-top of aabb
            if(fillTexture[i])
                    cs.setTexture(fillTexture[i]);
            else
                cs.setFillColor(Color::Blue);
            win.draw(cs, st);
            break;
        }
        case b2Shape::e_edge:
        // edge and chain cannot be textured
        {
            b2EdgeShape* s = dynamic_cast<b2EdgeShape*>(sh);
            VertexArray va(sf::Lines, 2);
            va[0].position = B2toSF(b->GetWorldPoint(s->m_vertex1));
            va[0].color = Color::White;
            va[1].position = B2toSF(b->GetWorldPoint(s->m_vertex2));
            va[1].color = Color::White;

            win.draw(va, st);
            break;
        }
        case b2Shape::e_chain: // chain is list of edges
        {
            b2ChainShape* s = dynamic_cast<b2ChainShape*>(sh);

            for (int32 i = 0; i < s->GetChildCount(); ++i) // for each edges in chain
            {
                // draw child edge
                b2EdgeShape edge;                
                s->GetChildEdge(&edge, i);
                VertexArray va(sf::Lines, 2);
                va[0].position = B2toSF(b->GetWorldPoint(edge.m_vertex1));
                va[0].color = Color::White;
                va[1].position = B2toSF(b->GetWorldPoint(edge.m_vertex2));
                va[1].color = Color::White;

                win.draw(va, st);
            }
            break;
        }
        }
    }
}
 
Is it a bug in SFML? Or is my code wrong?
« Last Edit: February 15, 2014, 02:35:53 pm by kubawal »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Textured shape - texture not rotate (SFML + Box2d)
« Reply #1 on: February 15, 2014, 07:55:51 pm »
Since the rotation is already applied when you create your shape, SFML doesn't know that it is rotated. To have the texture follow the rotation, you would have to rotate the SFML shape. I don't know if it's possible in your context (i.e. if you can access the unrotated points + rotation angle, rather than the final points).
Laurent Gomila - SFML developer

kubawal

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: Textured shape - texture not rotate (SFML + Box2d)
« Reply #2 on: February 16, 2014, 12:04:21 pm »
Must I use setOrigin() and setRotation()? Maybe can I use glRotatef() before creating shape?

/edit: It doesn't work.  :'(
I've got a screen like these:


My code:
// comments for this code are in first post
void Body::displayBody(RenderWindow &win, b2Body *b, Texture** fillTexture)
{
    bool autoInterpolate = true;

    int i = 0;
    for(b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext(), i++)
    {
        b2Shape* sh = f->GetShape();
        b2AABB aabb = f->GetAABB(0);
        Transform st = Transform::Identity;
        //st.rotate(RDtoDG(b->GetAngle()), B2toSF(aabb.GetCenter()));

        if(fillTexture[i] && autoInterpolate)
            fillTexture[i]->setSmooth(true);

        switch(sh->GetType())
        {
        case b2Shape::e_polygon:
        {          
            b2PolygonShape* s = dynamic_cast<b2PolygonShape*>(sh);
            ConvexShape cs(s->GetVertexCount());
            if(fillTexture[i])
                cs.setTexture(fillTexture[i]);
            else
                cs.setFillColor(Color::Red);

            cs.setOrigin(B2toSF(aabb.GetCenter() - aabb.lowerBound)); // GetCenter() is in body coordinates
            cs.setPosition(Vector2f() - cs.getOrigin()); // set left-top position to zero
            cs.rotate(RDtoDG(b->GetAngle()));

            for(int i = 0; i < s->GetVertexCount(); i++)
                cs.setPoint(i, B2toSF(b->GetWorldPoint(s->GetVertex(i))));
            win.draw(cs);
            break;
        }
        case b2Shape::e_circle:
        {
            static const float pi = 3.141592654f;
            b2CircleShape* s = dynamic_cast<b2CircleShape*>(sh);
            int pts = 30;
            ConvexShape cs(pts);
            if(fillTexture[i])
                cs.setTexture(fillTexture[i]);
            else
                cs.setFillColor(Color::Blue);

            cs.setOrigin(B2toSF(aabb.GetCenter() - aabb.lowerBound));
            cs.setPosition(B2toSF(b->GetWorldPoint(aabb.GetCenter())));
            cs.rotate(RDtoDG(b->GetAngle()));

            // calculating circle points manually
            float rad = B2toSF(s->m_radius);
            Vector2f center = B2toSF(b->GetWorldPoint(aabb.GetCenter()));
            for(int i = 0; i < pts; i++)
            {
                float angle = i * 2 * pi / pts - pi / 2;
                cs.setPoint(i, Vector2f(center.x + cos(angle) * rad, center.y + sin(angle) * rad));
            }
            win.draw(cs);
            break;
        }
        case b2Shape::e_edge:
        {
            b2EdgeShape* s = dynamic_cast<b2EdgeShape*>(sh);
            VertexArray va(sf::Lines, 2);
            va[0].position = B2toSF(b->GetWorldPoint(s->m_vertex1));
            va[0].color = Color::White;
            va[1].position = B2toSF(b->GetWorldPoint(s->m_vertex2));
            va[1].color = Color::White;

            win.draw(va);
            break;
        }
        case b2Shape::e_chain:
        {
            b2ChainShape* s = dynamic_cast<b2ChainShape*>(sh);

            for (int32 i = 0; i < s->GetChildCount(); ++i)
            {
                b2EdgeShape edge;
                s->GetChildEdge(&edge, i);
                VertexArray va(sf::Lines, 2);
                va[0].position = B2toSF(b->GetWorldPoint(edge.m_vertex1));
                va[0].color = Color::White;
                va[1].position = B2toSF(b->GetWorldPoint(edge.m_vertex2));
                va[1].color = Color::White;

                win.draw(va);
            }
            break;
        }
        }
    }
}
 
« Last Edit: February 16, 2014, 04:25:23 pm by kubawal »