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

Author Topic: Rendering into a sf::RenderTexture with OpenGL inside a class  (Read 2488 times)

0 Members and 1 Guest are viewing this topic.

robrene

  • Newbie
  • *
  • Posts: 5
    • View Profile
I'm trying to create an abstract base class that allows implementations to render into a sf::RenderTexture using raw OpenGL calls. A bit like this:

class GLBaseWidget : public Drawable, public Transformable {
 public:
  void update();  // Rerenders into texture if dirty bit set
  void draw(sf::RenderTarget&, sf::RenderStates) const override;  // Draws texture sprite to target
  math::Vec2i size() const;
  void rotateBy(const math::Vec3f&);

 protected:
  GLWidget(math::Vec2i size);
  void setDirtyBit();
  virtual void doRendering() = 0;

 private:
  sf::RenderTexture texture_;
  bool dirty_bit_;
  float rotation_matrix_[16];
};

This is a simplified version. The base class holds some state (the rotation matrix for example) and methods to modify the state. The update() method is where I am having trouble.

Obviously, the update() method checks for the dirty bit first. Then I want it to set up the projection and modelview matrices before calling the virtual doRendering() method. Afterwards, the OpenGL state should be back to the way it was before calling update().

I've written similar code using OpenGL Renderbuffers once, but not with gl::RenderTexture. Can someone guide me to the necessary steps for this to work? Ideally, the implementing classes will only push the actual vertices into the pipeline and everything will work.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #1 on: July 20, 2014, 02:28:41 pm »
Do you have a more precise problem? Have you tried something before asking for help?
Laurent Gomila - SFML developer

robrene

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #2 on: July 20, 2014, 02:46:39 pm »
I'm sorry for not adding more information immediately, I was in the process of trying some stuff, but I did not have anything tangential enough that I felt it would be worth showing. I can post the current state of things.

Here are current implementation details for the base class:

GLBaseWidget::GLBaseWidget(int width, int height) : dirty_bit_(true) {
  texture_.create(width, height, true);
}

void GLBaseWidget::update() {
  if (dirty_bit_) {
    texture_.setActive(true);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    float aspect = static_cast<float>(texture_.getTexture().getSize().x) / static_cast<float>(texture_.getTexture().getSize().y);
    float fov = 60.f;
    float near = 1.f / std::tan(fov / 2.f * (M_PI / 180.f)) / 100.f;
    glFrustum(-.01f, .01f, -.01f / aspect, .01f / aspect, near, 100.f);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(.0f, .0f, -4.0f);
    // TODO: rotation here

    renderToTexture();

    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    texture_.setActive(false);

    dirty_bit_ = false;
  }
}

void GLBaseWidget::draw(sf::RenderTarget& target, sf::RenderStates states) const {
  sf::Sprite sprite(texture_.getTexture());
  states.transform *= getTransform();
  target.draw(sprite, states);
}
 

Here is an example implementation that tries to draw just a triangle (PtWidget publicly inherits GLBaseWidget):

PtWidget::PtWidget(int width, int height)
: CubeWidget(width, height) {}

void PtWidget::renderToTexture() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
  glEnd();
}

This is the main function that calls this code:

int main() {
  sf::RenderWindow window(sf::VideoMode(512, 256), "Cubetest", sf::Style::Titlebar|sf::Style::Close);

  PtWidget pt_widget(256, 256);
  pt_widget.setPosition(0, 0);

  while (window.isOpen()) {
    window.pushGLStates();
    window.clear();
    window.draw(pt_widget);
    window.display();
    window.popGLStates();

    sf::Event event;
    while (window.waitEvent(event)) {
      if (event.type == sf::Event::Closed) window.close();
    }

    pt_widget.update();
  }

  return 0;
}

When I run it, I get some random textures from memory (from other applications or parts of the OS) in the left half of the window. When I close the window, the application "quits unexpectedly".
« Last Edit: July 20, 2014, 04:36:43 pm by robrene »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #3 on: July 20, 2014, 04:24:46 pm »
Where is dirty_bit_ changed to true?
Laurent Gomila - SFML developer

robrene

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #4 on: July 20, 2014, 04:38:22 pm »
Ah, that must be an artifact from boiling down the code to the bare necessities. I edited my example to set it to true, the bit was set to true in the constructor on my end as part of the rest of the state which I left out in this example.

The state is not used yet when rendering, so the code is functionally the same as it is written here.

To clarify: The problem persists.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #5 on: July 20, 2014, 04:49:11 pm »
Would you be able to write the same stuff in a complete and minimal code? I mean, no unneeded state or class, just a main() with the minimal code required to reproduce the problem.
Laurent Gomila - SFML developer

robrene

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #6 on: July 20, 2014, 07:44:41 pm »
I'm not sure if this is absolutely minimal, since something in here might be causing a side effect. This code does reproduce my error though. It shows a window of 512x256, with the left half being filled with what looks like random areas of video memory.

#include <cmath>
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>

int main() {
  sf::RenderWindow window(sf::VideoMode(512, 256), "Cubetest", sf::Style::Titlebar|sf::Style::Close);
  sf::RenderTexture texture;
  texture.create(256, 256, true);

  texture.setActive(true);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  float fov = 60.f;
  float near = 1.f / std::tan(fov / 2.f * (M_PI / 180.f)) / 100.f;
  glFrustum(-.01f, .01f, -.01f, .01f, near, 100.f);

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  glTranslatef(.0f, .0f, -4.0f);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3f( 0.0f,  1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
  glEnd();

  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

  texture.setActive(false);

  window.pushGLStates();
  window.clear();
  sf::Sprite sprite(texture.getTexture());
  window.draw(sprite);
  window.display();
  window.popGLStates();

  sf::Event event;
  while (window.waitEvent(event) && event.type != sf::Event::Closed) {}
  window.close();
  return 0;
}

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #7 on: July 20, 2014, 08:12:40 pm »
I can't help with the OpenGL stuff but I did test the code for you and it just displays a completely black window for me.
I don't think this could be considered "complete" code though, the variable near had already been #defined (so I adjusted its name) and M_PI wasn't defined (so I defined it as pi).
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: Rendering into a sf::RenderTexture with OpenGL inside a class
« Reply #8 on: July 21, 2014, 12:32:36 am »
You are never calling display() on the RenderTexture which probably causes your problem. I would also find it better if you used the clear() method instead of glClear().