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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Suslik

Pages: [1]
1
First of all, I've been using SFML for quite some time now both for my work and for educational purposes (my students really get a jumpstart into C++ graphics with it) and I'm really happy with most of its design decisions.

However, there's a few design decisions I don't like. One of them I wanted to discuss today regards native OpenGL rendering with SFML.

As far as I see, currently SFML supports native OpenGL rendering in a way when user theoretically can inject any kind of OpenGL code between native SFML calls and it should work as long as the user knows what they're doing. SFML even provides some basic API call to help doing so like sf::Texture::bind() or sf::Shader::bind(). However, in practice it turns out that in order to mix native OpenGL with SFML, user must have deeper OpenGL understanding than functionality he's actually going to use because of hidden states that SFML sets.

Here's an example of very basic OpenGL code injected into SFML:
sf::RenderWindow window(...);
while(window.isOpen())
{
  while(window.pullEvent(...)){...}
  window.setActive(1); //just to be sure
  float vertices[] = {0, 0, 0,   100, 0, 0,  0, 100, 0};
  int indices[] = {0, 1, 2};
  glEnableClientState (GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, vertices);
  glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

  window.display();
}
 
The code is very straightforward and it if you run it, it works great. Right? Wrong. Thing is, it works well *most of the time* because SFML has internal buffer bindings for its own rendering, for example here:
Code: [Select]
//RenderTarget.h, line 356
void RenderTarget::resetGLStates()
{
  //...
  glCheck(glEnableClientState(GL_VERTEX_ARRAY));
  glCheck(glEnableClientState(GL_COLOR_ARRAY));
  glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); 
  //...
}
And when the user calls glDrawElements() or any similar function, colors are actually read from internal SFML buffers and of course that's undefined behaviour. It may even not crash most of the time, but when it does, crash occurs in nvogl.dll(windows) and that's pretty hard to track especially for those learning OpenGL.

Similar problems arise when using native OpenGL texturing. Since most OpenGL users are used to normalized texture coordinates, it's very confusing to track down glMatrixMode(GL_TEXTURE) that SFML uses.

Yes I understand that it's easy to say that the user must not make any assumptions on any states left by SFML. But due to vast number of non-obvious states that the user may forget to set to default values, debugging such errors may prove to be very frustrating, especially when the same code works perfectly fine in native code without SFML. I really think SFML should provide some functionality similar to resetGlStates(), but instead of resetting states for SFML usage, reset them to default OpenGL ones(matrices, client buffers, etc).

2
Ok, here's the minimal code:
#include <SFML/Graphics.hpp>

sf::RenderWindow *window1, *window2;
bool isRunning = 1;

void ThreadFunc1()
{
  while(isRunning)
  {
    window1->clear();
    window1->display();
  }
}

void ThreadFunc2()
{
  while(isRunning)
  {
    window2->clear();
    window2->display();
  }
}

int main()
{
  window1 = new sf::RenderWindow(sf::VideoMode(800, 600), "Awesome window");
  window1->setActive(false);
  sf::Thread thread1(ThreadFunc1);
  thread1.launch();

  window2 = new sf::RenderWindow(sf::VideoMode(800, 600), "Not as awesome window as the first one but still great");
  window2->setActive(false);
  sf::Thread thread2(ThreadFunc2);
  thread2.launch();

  while(isRunning)
  {
    sf::Event event;

    while(window1->pollEvent(event))
    {
      if(event.type == sf::Event::Closed)
      {
        isRunning = 0;
      }
    }
    while(window2->pollEvent(event))
    {
      if(event.type == sf::Event::Closed)
      {
        isRunning = 0;
      }
    }

    printf("we're alive\n");
  }
}
 
It creates 2 windows and a separate rendering thread for each of them while processing window events in the main thread. It works just fine if you compile and run it. However if you have some kind of recording software that captures OpenGL or D3D context running in your system, after running this test program for a few secods you get this:

or this:

but most often this:

When the crash happens, stack pointer always points either to window1->display() or window2->display().

The crash happens with different kinds of recording software like Bandicam, Action! and a few others when they're in OpenGL/D3D recording mode. It happens when these programs are just running and not even recording anything. The test program may run for a few seconds, sometimes it may semi-freeze for a second or two and reliably crashes after 3-10 seconds of running.

Any ideas how to work this around or reason why this happens?

3
Houston, we've got a problem.

So I'm writing a plugin for some random program and using SFML window to render some debug stuff. The plugin has a structure like this:

struct MySystem
{
  MySystem()
  {
    window = new sf::RenderWindow(...);
  }
  ~MySystem()
  {
    delete window;
  }
  void Update()
  {
    sf::Event event;
    while(window->pollEvent(event);
  }
  sf::RenderWindow *window;
};
MySystem *mySystem;
void DLL_API PluginInit()
{
  mySystem = new MySystem();
}
void DLL_API PluginUpdate()
{
  mySystem->Update();
}
void DLL_API PluginRelease()
{
  delete mySystem;
}
 

So far, so good. Now imagine there's a button "stop plugin" in the program I'm making the plugin for. The button apparently has an event function like this:
void ProgramImMakingPluginFor::OnPluginStopButtonPressed()
{
  PluginRelease();
}
 

What happens is this: the program crashes when I hit the "StopPlugin" button and crashed stack trace points to my line with while(window->pollEvent(event)); A couple of restless nights pointed out that what actually happens is this:

During my Update() when I call window->pollEvent(event) instead of processing messages addressed to my window it processes messages to non-sfml windows as well. sf::Window::pollEvent() calls sf::Window::popEvent() that calls WindowImplWin32::processEvents() that looks like this:
void WindowImplWin32::processEvents()
{
    // We process the window events only if we own it
    if (!m_callback)
    {
        MSG message;
        while (PeekMessageW(&message, NULL/*SIC*/, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&message);
            DispatchMessageW(&message);
        }
    }
}
 
And during MySystem::Update() pollEvent() calls ProgramImMakingPluginFor::OnPluginStopButtonPressed() that calls PluginRelease() and destroys mySystem. Apparently bad things happen if inside mySystem->Update() you destroy instance of mySystem.

Two questions:
1) Shouldn't it have been
while (PeekMessageW(&message, m_handle, 0, 0, PM_REMOVE))
 
instead of
while (PeekMessageW(&message, NULL, 0, 0, PM_REMOVE))
 
?
2) Which options do I have for a workaround?

4
Window / Multiple windows, top one does not receive input
« on: October 30, 2014, 02:21:14 am »
Minimal code:
#include <SFML/Graphics.hpp>
int main()
{
        sf::RenderWindow largerWindow(sf::VideoMode(800, 600), "Larger window");
        sf::RenderWindow smallerWindow(sf::VideoMode(200, 100), "Smaller window");

        while (smallerWindow.isOpen() || largerWindow.isOpen())
        {
                sf::Event event;
                while (smallerWindow.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                        smallerWindow.close();
                }
                while (largerWindow.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                        largerWindow.close();
                }
        }
        return 0;
}

 
The code creates a larger window and a smaller one on top of it:


The smaller window does not receive mouse input: you cannot drag or close it while it's above larger window. When you move larger window away you can select it though and after that it works as intended. Problem occurs only after creating windows - smaller one looks on top of larger one but acts as if it was under it.

Tested on Windows 7.

5
Graphics / glDrawElements() + sf::Text = Access Violation in nvoglv32.dll
« on: October 28, 2014, 04:19:53 am »
Hey folks. Situation is as follows.
I render some debug text like this:
    sf::Text line0("Some text to render", debugInfoFont, 20);
    line0.setPosition(10.0f, 20.0f * 1);
    debugInfoWindow->draw(line0);
    //debugInfoWindow->resetGLStates(); //does not help
 
Then I render native opengl geometry like this:
      glEnableClientState (GL_VERTEX_ARRAY);
      glVertexPointer(3, GL_FLOAT, sizeof(Mesh::Vertex), &(vertices[0].pos.x));
      glEnableClientState(GL_NORMAL_ARRAY);
      glNormalPointer(GL_FLOAT, sizeof(Mesh::Vertex), &(vertices[0].norm.x));
      glDisableClientState(GL_TEXTURE_COORD_ARRAY); //just to ensure no texture coordinates are read
      glDrawElements(GL_TRIANGLES, faces.size() * 3, GL_UNSIGNED_INT, faces[0].incidentVertices);
 
And sometimes glDrawElements causes AV in nvoglv32.dll. Emphasis on "sometimes" because I was even unable to make a minimal code: even the large project I'm working on does not always crash. Sometimes it works just fine, sometimes it crashes on 2nd program loop iteration. Debug/Release do not affect behavior in any way. Program does not crash if I disable either text rendering or glDrawElements() calls. Looks like text rendering leaves some buffers unflushed and it breaks something later. I tried adding window->display() after rendering the text in hope that it'll flush the buffers but the program still crashes just the same way.

Also some debugging revealed that if I wrap my text rendering code into this:
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
{
    sf::Text line2("howdy", debugInfoFont, 20);
    line2.setPosition(10.0f, 20.0f * 3);
    debugInfoWindow->draw(line2);
}
glPopClientAttrib();
 
the program no longer crashes but after rendering the 1st frame text disappears. Apparently it has something to do with SFML not resetting some of its buffers between calls, but how can that be helped?

Any suggestions?

6
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;
}

Pages: [1]
anything