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

Author Topic: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry  (Read 6570 times)

0 Members and 1 Guest are viewing this topic.

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
So the problem is as follows:
- I have a fragment shader that uses gl_TexCoord[0]
- I have a simple vertex array with normalized texture coords(0..1) and the shader works fine with this geometry
- But if I render any geometry with a texture prior to rendering geometry with a shader, gl_TexCoord[0] gets messed and returns non-normalized values instead of what I'm trying to pass.

Reason:
After rendering any kind of geometry with a texture, OpenGL texture matrix gets messed and multiplies my normalized values so that they become non-normalized.

Minimal code:
C++ - side
#include <SFML/Graphics.hpp>

sf::RenderWindow window(sf::VideoMode(600, 600), "This is awesome!");
sf::Shader shader;
sf::Texture randomTexture;

void Render()
{
  sf::Vertex vertices[4];

  vertices[0].texCoords.x = 0.0f;
  vertices[0].texCoords.y = 0.0f;
  vertices[0].position.x  = 0.0f;
  vertices[0].position.y  = 0.0f;

  vertices[1].texCoords.x = float(randomTexture.getSize().x);
  vertices[1].texCoords.y = 0.0f;
  vertices[1].position.x  = float(window.getSize().x);
  vertices[1].position.y  = 0.0f;

  vertices[2].texCoords.x = float(randomTexture.getSize().x);
  vertices[2].texCoords.y = float(randomTexture.getSize().y);
  vertices[2].position.x  = float(window.getSize().x);
  vertices[2].position.y  = float(window.getSize().y);

  vertices[3].texCoords.x = 0.0f;
  vertices[3].texCoords.y = float(randomTexture.getSize().y);
  vertices[3].position.x  = 0.0f;
  vertices[3].position.y  = float(window.getSize().y);

  //window.resetGLStates(); // does not work
  //window.pushGLStates(); // does not work
  window.draw(vertices, 4, sf::Quads, &randomTexture);
  //window.popGLStates();

  vertices[0].texCoords.x = 0.0f;
  vertices[0].texCoords.y = 0.0f;

  vertices[1].texCoords.x = 1.0f;
  vertices[1].texCoords.y = 0.0f;

  vertices[2].texCoords.x = 1.0f;
  vertices[2].texCoords.y = 1.0f;

  vertices[3].texCoords.x = 0.0f;
  vertices[3].texCoords.y = 1.0f;

  window.draw(vertices, 4, sf::Quads, &shader);
}


int main()
{
  randomTexture.loadFromFile("data/Sample.jpg");
  shader.loadFromFile("data/TestShader.frag", sf::Shader::Fragment);
  //shader.loadFromFile("data/TestVertexShader.vert", "data/TestShader.frag"); //using a dummy vertex shader looks like the best workaround
  while(window.isOpen())
  {
    sf::Event event;
    while (window.pollEvent(event))
    {
      if (event.type == sf::Event::Closed)
        window.close();
    }
    window.clear();
    Render();
    window.display();
  }
  return 0;
}
 

GLSL fragment shader:
void main()
{
  gl_FragColor = vec4(gl_TexCoord[0].xy, 0.0, 1.0);
}

Expected image is "Right.png" in the attachment, what I actually get is "Wrong.png".
Additional info:
The problem was discussed in numerous threads: http://en.sfml-dev.org/forums/index.php?topic=10148.0, http://en.sfml-dev.org/forums/index.php?topic=8282.15 https://github.com/SFML/SFML/issues/235 But I think it did have a lot of irrelevant info. Do note that commenting window.draw(vertices, 4, sf::Quads, &randomTexture); makes the shader work as intended(it means gl_TexCoord[0] reverts to a proper range of 0..1 instead of 0..1/width which's wrong). Image that I actually get "Wrong.png" is not entirely black, it's actual color at bottom-right corner is vec4(1.0 / width, 1.0 / height, 0.0, 1.0), since my image is ~1024 pixels wide, the color looks black.


Workarounds:
One would expect that using window.resetGlStates() would restore texture matrix and solve the problem, but it does not. window.pushGlStates(), window.popGlStates() around textured geometry render call does not solve the problem either. Resetting OpenGL texture matrix manually does solve the problem but it's more of a clutch than a solution. The best workaround for me was to use a vertex shader that ignores texture matrix and directly assigns gl_MultiTexCoord0 to gl_TexCoord[0]:
void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_FrontColor = gl_Color;
}
« Last Edit: August 31, 2014, 01:33:10 pm by Suslik »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #1 on: August 31, 2014, 09:20:37 pm »
SFML uses non-normalized (pixel) coordinates. If you intend to specify your own coordinates normalized, you will have to tell SFML that it should bind the texture without altering the texture matrix.

This can be done with:
sf::Texture::bind(&your_texture, sf::Texture::Normalized);

When SFML unbinds any texture (yours or its own internally used ones), it will always reset the matrix back to identity. When you pass the texture to bind as part of a RenderState, it assumes that you want to bind it using pixel coordinates. You can simply bind the texture specifying normalized coordinates yourself before the draw and unbinding it after.

As for your workaround, it isn't really a workaround. GLSL doesn't require you to do anything you don't need to. If you use normalized texture coordinates anyway, you shouldn't even make use of the texture matrix. All matrix stacks were deprecated from OpenGL 3.0 onwards and got removed from the core profile of any 3.2+ context. Just move away from relying on matrix stacks in your shaders and you should be set for the future ;).
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #2 on: August 31, 2014, 10:51:09 pm »
SFML uses non-normalized (pixel) coordinates. If you intend to specify your own coordinates normalized, you will have to tell SFML that it should bind the texture without altering the texture matrix.

This can be done with:
sf::Texture::bind(&your_texture, sf::Texture::Normalized);
Yes, that's how it's supposed to work. Unfortunately it does not work so. Problem was already discussed here: https://github.com/SFML/SFML/issues/235 binding texture with sf::Texture::Pixels changes texture matrix, while sf::Texture::Normalized does not revert it to identity as expected.

When SFML unbinds any texture (yours or its own internally used ones), it will always reset the matrix back to identity. When you pass the texture to bind as part of a RenderState, it assumes that you want to bind it using pixel coordinates. You can simply bind the texture specifying normalized coordinates yourself before the draw and unbinding it after.
No. Again, it does not work as one would expect. Following Render() code produces exactly the same wrong image(commented lines are changed):
void Render()
{
  sf::Vertex vertices[4];

  vertices[0].texCoords.x = 0.0f;
  vertices[0].texCoords.y = 0.0f;
  vertices[0].position.x  = 0.0f;
  vertices[0].position.y  = 0.0f;

  vertices[1].texCoords.x = float(randomTexture.getSize().x);
  vertices[1].texCoords.y = 0.0f;
  vertices[1].position.x  = float(window.getSize().x);
  vertices[1].position.y  = 0.0f;

  vertices[2].texCoords.x = float(randomTexture.getSize().x);
  vertices[2].texCoords.y = float(randomTexture.getSize().y);
  vertices[2].position.x  = float(window.getSize().x);
  vertices[2].position.y  = float(window.getSize().y);

  vertices[3].texCoords.x = 0.0f;
  vertices[3].texCoords.y = float(randomTexture.getSize().y);
  vertices[3].position.x  = 0.0f;
  vertices[3].position.y  = float(window.getSize().y);

  window.draw(vertices, 4, sf::Quads, &randomTexture);

  vertices[0].texCoords.x = 0.0f;
  vertices[0].texCoords.y = 0.0f;

  vertices[1].texCoords.x = 1.0f;
  vertices[1].texCoords.y = 0.0f;

  vertices[2].texCoords.x = 1.0f;
  vertices[2].texCoords.y = 1.0f;

  vertices[3].texCoords.x = 0.0f;
  vertices[3].texCoords.y = 1.0f;

  sf::Texture::bind(&randomTexture, sf::Texture::Normalized); //this line is changed. image is still wrong.
  //sf::Texture::bind(0, sf::Texture::Normalized); //has no effect either
  window.draw(vertices, 4, sf::Quads, &shader);
}
 

As for your workaround, it isn't really a workaround. GLSL doesn't require you to do anything you don't need to. If you use normalized texture coordinates anyway, you shouldn't even make use of the texture matrix. All matrix stacks were deprecated from OpenGL 3.0 onwards and got removed from the core profile of any 3.2+ context. Just move away from relying on matrix stacks in your shaders and you should be set for the future ;).
I don't use texture matrix at all, SFML does. So I have to make a vertex shader that skips multiplication by texture matrix that I don't need.
« Last Edit: August 31, 2014, 10:52:53 pm by Suslik »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #3 on: August 31, 2014, 11:49:06 pm »
Yes, that's how it's supposed to work. Unfortunately it does not work so. Problem was already discussed here: https://github.com/SFML/SFML/issues/235 binding texture with sf::Texture::Pixels changes texture matrix, while sf::Texture::Normalized does not revert it to identity as expected.
I already understood that, and Laurent already explained it in the GitHub issue. You are mixing sfml-graphics rendering (using pixel coordinates) and what you think is "OpenGL rendering" for lack of a better term. If you are using .draw() to render stuff, it counts as sfml-graphics rendering, and the convention is that you use pixel coordinates. If you want to use normalized texture coordinates, then you are probably better off doing the rendering directly with OpenGL code, which is what sf::Texture::bind() with sf::Texture::Normalized was for: interaction with OpenGL. You can't mix and match pixel and normalized coordinates if you just rely on sfml-graphics to do the rendering for you. SFML doesn't expect the user to bind a texture with sf::Texture::Normalized while at the same time binding a texture with pixel coordinates somewhere internally, so it also doesn't reset it for you.

No. Again, it does not work as one would expect. Following Render() code produces exactly the same wrong image(commented lines are changed):
In this line
window.draw(vertices, 4, sf::Quads, &randomTexture);
you pass the texture to SFML as part of a RenderState. You are telling SFML to bind it using pixel coordinates.

In these lines
sf::Texture::bind(&randomTexture, sf::Texture::Normalized); //this line is changed. image is still wrong.
//sf::Texture::bind(0, sf::Texture::Normalized); //has no effect either
window.draw(vertices, 4, sf::Quads, &shader);
you bind the texture using normalized coordinates. Like I said above, don't mix modes. Stick to one mode and everything should work fine. If you want to use RenderStates then you will have to use pixel coordinates everywhere. If you don't need to pass your textures as part of RenderStates, then you can use normalized coordinates everywhere if you want, because SFML won't try to force you to use pixel coordinates any more.

And to add to what I said in my previous post, calling .resetGLStates() resets the GL states to the values required by sfml-graphics to function properly. It doesn't reset the GL states to the default values that they had when the context was created, although some people might understand it this way.

I don't use texture matrix at all, SFML does. So I have to make a vertex shader that skips multiplication by texture matrix that I don't need.
It is not uncommon to create multiple shaders for different coordinate systems. Just because SFML uses the texture matrix somewhere, doesn't mean you have to use the texture matrix as well, if you know that the coordinates your shader receives will always be normalized. Shaders are very flexible. You can change conventions as you wish. Unless you plan on using the same shader to render sfml-graphics objects (sf::Sprite, sf::Shape, etc.) as well as your custom vertex objects, you won't have to make sure that it is compatible with SFML's rendering. I also recommend splitting shaders up depending on the conventions that are used in them. Although some people might be inclined to toss everything into one gigantic "uber shader", it isn't really recommended from a performance and maintainability standpoint.

I am wondering, is there a reason why you aren't just resorting to using raw OpenGL in your project? :) Your code already looks very similar to what the equivalent OpenGL code would look like, and you wouldn't be running into these issues if you went down the raw OpenGL route, at least for some portions of your code. SFML has had a tradition of being very picky in how it wants the user to render stuff but this is probably going to change in the future ;D.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #4 on: September 01, 2014, 12:36:55 am »
You can't mix and match pixel and normalized coordinates if you just rely on sfml-graphics to do the rendering for you.
So the question is, why? It does not seem like a huge technical deal to set texture matrix to a proper one when assigning a texture as sf::Texture::Normalized. I understand that it's quite challenging to add for example multitexturing or geometry shaders to existing SFML API but seriously, isnt this "do not mix coordinate conventions in one program" sound a little artifitial?

You can change conventions as you wish.
So why does SFML change it internally and does not have any kind of functionality to revert Pixel convention back to normalized? Why should I call SFML API function to set coordinates to non-normalized, but use OGL function to reset matrix back to normalized mode, that just does not make sense to me.


I am wondering, is there a reason why you aren't just resorting to using raw OpenGL in your project? :) Your code already looks very similar to what the equivalent OpenGL code would look like, and you wouldn't be running into these issues if you went down the raw OpenGL route, at least for some portions of your code. SFML has had a tradition of being very picky in how it wants the user to render stuff but this is probably going to change in the future ;D.
I've been using raw opengl for ages. I don't like gapi-dependent stuff hanging around in business code so for a few years I've been developing my framework-opengl-wrapper until I found SFML that looks like 90% identical to my framework but supports network and audio as well. And I don't like using raw OpenGL calls when that's not really necessary. It's ok to create a floating-point texture, 3d texture, add a geometry shader to sfml program via native OpenGL code, but srsly reverting texture coordinate convention is not the case when it should be necessary.
« Last Edit: September 01, 2014, 12:39:34 am by Suslik »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #5 on: September 01, 2014, 12:50:09 am »
I think you're missing the key point of binary's reply.  Though it's very possible I'm misunderstanding something myself, here's my attempt at a simpler explanation:

The documentation for sf::Texture::bind() states:
Quote
This function is not part of the graphics API, it mustn't be used when drawing SFML entities. It must be used only if you mix sf::Texture with OpenGL code.

This counts as "drawing SFML entities":
window.draw(vertices, 4, sf::Quads, &shader);

There are similar statements in the documentation for resetGLStates() and all the other functions that exist solely for interoperability with "raw" OpenGL.

As far as I know, none of those functions are meant to have any effect on the result of an SFML draw() call.
« Last Edit: September 01, 2014, 12:57:39 am by Ixrec »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #6 on: September 01, 2014, 11:42:08 am »
I've cleaned the issue on the tracker. Please don't post there until the discussion ends here and we all agree about what to do (or not do) ;)
Laurent Gomila - SFML developer

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #7 on: September 01, 2014, 11:55:04 am »
I think you're missing the key point of binary's reply.  Though it's very possible I'm misunderstanding something myself, here's my attempt at a simpler explanation:

The documentation for sf::Texture::bind() states:
Quote
This function is not part of the graphics API, it mustn't be used when drawing SFML entities. It must be used only if you mix sf::Texture with OpenGL code.

This counts as "drawing SFML entities":
window.draw(vertices, 4, sf::Quads, &shader);

There are similar statements in the documentation for resetGLStates() and all the other functions that exist solely for interoperability with "raw" OpenGL.

As far as I know, none of those functions are meant to have any effect on the result of an SFML draw() call.
Ok let's pretend that it makes sense and I cannot mix SFML drawing call and GLSL. Following example uses sf::Texture::Bind() only in conjunction with native OpenGL - the way I'm supposed to use this:
void Render()
{
  glEnable(GL_TEXTURE_2D);

  sf::Texture::bind(&randomTexture, sf::Texture::Pixels);
  sf::Shader::bind(0);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex2f(-1.0, -1.0);

    glTexCoord2f(randomTexture.getSize().x, 0.0);
    glVertex2f(1.0, -1.0);

    glTexCoord2f(randomTexture.getSize().x, randomTexture.getSize().y);
    glVertex2f(1.0, 1.0);

    glTexCoord2f(0, randomTexture.getSize().y);
    glVertex2f(-1.0, 1.0);
  glEnd();

  sf::Texture::bind(&randomTexture, sf::Texture::Normalized);
  sf::Shader::bind(&shader);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0);
    glVertex2f(-1.0, -1.0);

    glTexCoord2f(1.0, 0.0);
    glVertex2f(1.0, -1.0);

    glTexCoord2f(1.0, 1.0);
    glVertex2f(1.0, 1.0);

    glTexCoord2f(0, 1.0);
    glVertex2f(-1.0, 1.0);
  glEnd();
}
 
Result is identical: sf::Texture::bind(&randomTexture, sf::Texture::Pixels); messes up texture matrix and   sf::Texture::bind(&randomTexture, sf::Texture::Normalized); does not revert it back to identity which certainly is not what one would expect from the code.
« Last Edit: September 01, 2014, 11:57:05 am by Suslik »

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #8 on: September 01, 2014, 12:05:01 pm »
Seriously let me do your job. This is sf::Texture::bind() code from your repository:
void Texture::bind(const Texture* texture, CoordinateType coordinateType)
{
    ensureGlContext();

    if (texture && texture->m_texture)
    {
        // Bind the texture
        glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture));

        // Check if we need to define a special texture matrix
        if ((coordinateType == Pixels) || texture->m_pixelsFlipped)
        {
            GLfloat matrix[16] = {1.f, 0.f, 0.f, 0.f,
                                  0.f, 1.f, 0.f, 0.f,
                                  0.f, 0.f, 1.f, 0.f,
                                  0.f, 0.f, 0.f, 1.f};

            // If non-normalized coordinates (= pixels) are requested, we need to
            // setup scale factors that convert the range [0 .. size] to [0 .. 1]
            if (coordinateType == Pixels)
            {
                matrix[0] = 1.f / texture->m_actualSize.x;
                matrix[5] = 1.f / texture->m_actualSize.y;
            }

            // If pixels are flipped we must invert the Y axis
            if (texture->m_pixelsFlipped)
            {
                matrix[5] = -matrix[5];
                matrix[13] = static_cast<float>(texture->m_size.y) / texture->m_actualSize.y;
            }

            // Load the matrix
            glCheck(glMatrixMode(GL_TEXTURE));
            glCheck(glLoadMatrixf(matrix));

            // Go back to model-view mode (sf::RenderTarget relies on it)
            glCheck(glMatrixMode(GL_MODELVIEW));
        }
    }
    else
    {
        // Bind no texture
        glCheck(glBindTexture(GL_TEXTURE_2D, 0));

        // Reset the texture matrix
        glCheck(glMatrixMode(GL_TEXTURE));
        glCheck(glLoadIdentity());

        // Go back to model-view mode (sf::RenderTarget relies on it)
        glCheck(glMatrixMode(GL_MODELVIEW));
    }
}
 
Now would you kindly notice that if (texture && texture->m_texture) is satisfied and if (coordinateType == Normalized), texture matrix remains as it was before the call instead of being reset?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #9 on: September 01, 2014, 12:10:08 pm »
Yes, this is an optimization. If you mix SFML and OpenGL the way it's meant to be (which you don't in your example), this should normally not break anything on your side.

And please calm down. Being more and more aggressive won't help you to get meaningful and detailed answers from us.
Laurent Gomila - SFML developer

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #10 on: September 01, 2014, 12:35:50 pm »
Ok. As far as I can understand this code not working is intended behavior:
  sf::Texture::bind(&randomTexture, sf::Texture::Pixels);
  //render something with non-normalized coordinates
  sf::Texture::bind(&randomTexture, sf::Texture::Normalized);
  //render something with normalized coordinates
 
Then I have a question why this code is intended not to work?

If this is due to optimization then using glBindTexture() usually takes way more time than glMatrixMode(GL_TEXTURE) + glLoadIdentity(); Also why do window.push/popGlStates() or window.resetGlStates() not affect texture matrix so one has to use native gl functions to reset it?
« Last Edit: September 01, 2014, 12:41:20 pm by Suslik »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #11 on: September 01, 2014, 01:20:18 pm »
Quote
Then I have a question why this code is intended not to work?
Pixel coordinates are designed for internal use in sfml-graphics. It was never meant to be used with raw OpenGL, so we've never made it work for this use case. Everybody uses normalized coordinates with OpenGL, this is the intended (and only, without texture matrix hacks) way of handling texture coordinates, so I'd say, don't use pixel coordinates just because SFML provides this option.

Quote
Also why do window.push/popGlStates() or window.resetGlStates() not affect texture matrix so one has to use native gl functions to reset it?
sf::Texture::bind is just a convenience wrapper, it shouldn't be considered a sfml-graphics call, it acts as if you called glBindTexture yourself, and therefore anything that it changes is not affected by push/popGLStates.

The real issue here is:
1. understand how SFML and OpenGL are meant to be mixed (admittedly this is not always simple, this is an area that needs to be improved in the future)
2. do it right ;)
« Last Edit: September 01, 2014, 01:21:58 pm by Laurent »
Laurent Gomila - SFML developer

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #12 on: September 01, 2014, 01:38:50 pm »
Quote
Then I have a question why this code is intended not to work?
Pixel coordinates are designed for internal use in sfml-graphics. It was never meant to be used with raw OpenGL, so we've never made it work for this use case. Everybody uses normalized coordinates with OpenGL, this is the intended (and only, without texture matrix hacks) way of handling texture coordinates, so I'd say, don't use pixel coordinates just because SFML provides this option.

Quote
Also why do window.push/popGlStates() or window.resetGlStates() not affect texture matrix so one has to use native gl functions to reset it?
sf::Texture::bind is just a convenience wrapper, it shouldn't be considered a sfml-graphics call, it acts as if you called glBindTexture yourself, and therefore anything that it changes is not affected by push/popGLStates.

The real issue here is:
1. understand how SFML and OpenGL are meant to be mixed (admittedly this is not always simple, this is an area that needs to be improved in the future)
2. do it right ;)
I think you're confusing raw OpenGL and GLSL safety measures. If the user resorts to calling native OpenGL function he indeed should have good reasons to do so and pay extra attention. Another area is using GLSL that's natively supported by SFML and that gets messed without making any raw OpenGL calls from C++ side. Latter can be hardly considered normal.

I suggest that we stop defending faulty design and find a decent solution how to avoid such troubles in future.

I understand that resetting texture matrix in sf::Texture::bind() may theoretically impact performance or cause unexpected behaviour for those who set texture matrix prior to this call. My proposal is rename sf::Texture::CoordinateType::Normalized to sf::Texture::CoordinateType::Current or ::NoChange and make it default. Actual normalized mode should be added as well, usage is as follows:
  //this call resets texture matrix to identity instead of what it does now
  sf::Texture::bind(&tex, sf::Texture::Normalized);
  //these calls are identical and they act as current sf::Texture::Normalized
  //it means they just bind the texture without affecting texture matrix
  sf::Texture::bind(&tex, sf::Texture::Current);
  sf::Texture::bind(&tex); //this call is identical to just calling glBindTexture() since it does not change texture matrix
  //this call acts exactly as current sf::Texture::Pixels
  sf::Texture::bind(&tex, sf::Texture::Pixels);
 

Additionally I propose resetting texture matrix whenever current texture is unbound, because sfml texture matrix is useful only for the texture it was built for and resetting it on unbind is what one would expect including your own team members:
When SFML unbinds any texture (yours or its own internally used ones), it will always reset the matrix back to identity.

<....>
You can simply bind the texture specifying normalized coordinates yourself before the draw and unbinding it after.
« Last Edit: September 01, 2014, 01:58:41 pm by Suslik »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #13 on: September 01, 2014, 01:57:52 pm »
Quote
I think you're confusing raw OpenGL and GLSL safety measures. If the user resorts to calling native OpenGL function he indeed should have good reasons to do so and pay extra attention. Another area is using GLSL that's natively supported by SFML and that gets messed without making any raw OpenGL calls from C++ side. Latter can be hardly considered normal.
I based my answers on your latest code example, which uses raw OpenGL calls. If it's not the case then please don't post such an example, but rather something that reflects the real issue (or maybe you did, at the beginning of the discussion that I didn't read) ;)
Laurent Gomila - SFML developer

Suslik

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: [SFML 2.1 bug] Messed texture matrix after rendering textured geometry
« Reply #14 on: September 01, 2014, 02:06:40 pm »
In the initial post I've explained the problem that gl_TexCoord[0] gets messed if a textured geometry(with Pixel coordinate type) is rendered prior to shadered geometry that does not even use a texture or have texture assigned by a uniform. There are no OpenGL calls in the original post. Someone suggested that mixing OpenGL draw routines and SFML is a bad idea(even though there was no OpenGL code to start with):
The documentation for sf::Texture::bind() states:
Quote
This function is not part of the graphics API, it mustn't be used when drawing SFML entities. It must be used only if you mix sf::Texture with OpenGL code.
So I made another example that used only sf::Texture::bind() and native OpenGL code without SFML draw routines to demonstrate that the problem is not related to mixing SFML and OpenGL draw calls but solely to texture binding.

And now you're telling me I'm mixing OpenGL and SFML in a wrong way. Next time please do try reading the original post because actual problem is stated there. Every other example I posted was only for demonstrating others that the problem exists in different usage scenarios.
« Last Edit: September 01, 2014, 02:15:47 pm by Suslik »