matus-chochlik / oglplus

OGLplus is a collection of open-source, cross-platform libraries which implement an object-oriented facade over the OpenGL® (version 3 and higher) and also OpenAL® (version 1.1) and EGL (version 1.4) C-language APIs. It provides wrappers which automate resource and object management and make the use of these libraries in C++ safer and more convenient.
http://oglplus.org/
Boost Software License 1.0
491 stars 72 forks source link

oglplus and multiple OpenGL context. #90

Closed ndelb closed 9 years ago

ndelb commented 9 years ago

Hi, First of all, thank you for making oglplus, it's really great. I have been having issues setting up a program that uses glfw3 with multiple windows and multiple OpenGL contexts in combination with oglplus and GLEW. I had a look at the examples but I could not find any that uses multiple windows. Do you think you could add to your examples one that shows how to set up oglplus with multiple glfw3 windows? If you want I can try to make a short example of multiple windows with glfw3 but without oglplus. If it might help. Thank you very much.

Nic

matus-chochlik commented 9 years ago

Hi, Thanks. If you can provide an example using multiple windows I will port it to OGLplus.

BR

Matus

ndelb commented 9 years ago

Hi Matus,

The following is a simple example of multiple window with glfw3. From what I understand each window has its own OpenGL context. This is a very simplified version of my code, as I normally use one class per window and they use texutres, shaders and GLEW. But hopefully it provides a good illustration.

#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;

static void error_callback(int error, const char* description)
{
  fputs(description, stderr);
}
static void key_callback1(GLFWwindow* window1, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window1, GL_TRUE);
  else
  {
    cout << "Received key input from window 1:" << endl;
    cout << "   key:"<<key<<", scancode:"<<scancode<<", action:"<<action<<", mods:"<<mods<<endl;
  }
}
static void key_callback2(GLFWwindow* window2, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window2, GL_TRUE);
  else
  {
    cout << "Received key input from window 2:" << endl;
    cout << "   key:"<<key<<", scancode:"<<scancode<<", action:"<<action<<", mods:"<<mods<<endl;
  }
}

int main(void)
{
  GLFWwindow* window1;
  GLFWwindow* window2;
  glfwSetErrorCallback(error_callback);
  if (!glfwInit())
    exit(EXIT_FAILURE);
  window1 = glfwCreateWindow(640, 480, "Window 1", NULL, NULL);
  window2 = glfwCreateWindow(640, 480, "Window 2", NULL, NULL);
  if (!window1 || !window2)
  {
    glfwTerminate();
    exit(EXIT_FAILURE);
  }
  glfwSetWindowPos  (window2, 641, 0);
  glfwSetKeyCallback(window1, key_callback1);
  glfwSetKeyCallback(window2, key_callback2);
  bool running = true;
  while(running)
  {
    //check if windows should close
    if(glfwWindowShouldClose(window1))
      running = false;
    if(glfwWindowShouldClose(window2))
      running = false;
    //fist draw in window 1
    glfwMakeContextCurrent(window1);
    {
      float ratio;
      int width, height;
      glfwGetFramebufferSize(window1, &width, &height);
      ratio = width / (float) height;
      glViewport(0, 0, width, height);
      glClear(GL_COLOR_BUFFER_BIT);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);
      glBegin(GL_TRIANGLES);
      glColor3f(1.f, 0.f, 0.f);
      glVertex3f(-0.6f, -0.4f, 0.f);
      glColor3f(0.f, 1.f, 0.f);
      glVertex3f(0.6f, -0.4f, 0.f);
      glColor3f(0.f, 0.f, 1.f);
      glVertex3f(0.f, 0.6f, 0.f);
      glEnd();
      glfwSwapBuffers(window1);
    }
    //then draw in window 2
    glfwMakeContextCurrent(window2);
    {
      float ratio;
      int width, height;
      glfwGetFramebufferSize(window2, &width, &height);
      ratio = width / (float) height;
      glViewport(0, 0, width, height);
      glClear(GL_COLOR_BUFFER_BIT);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glRotatef(-(float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);
      glBegin(GL_QUADS);
      glColor3f(0.f, 0.f, 0.f);
      glVertex3f(-0.5f, -0.5f, 0.f);
      glColor3f(1.f, 0.f, 0.f);
      glVertex3f( 0.5f, -0.5f, 0.f);
      glColor3f(1.f, 1.f, 0.f);
      glVertex3f( 0.5f,  0.5f, 0.f);
      glColor3f(0.f, 1.f, 0.f);
      glVertex3f(-0.5f,  0.5f, 0.f);
      glEnd();
      glfwSwapBuffers(window2);
    }
    glfwPollEvents();
  }
  glfwDestroyWindow(window1);
  glfwDestroyWindow(window2);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}

Kind Regards, Nic

matus-chochlik commented 9 years ago

This example uses GL < 3.0, do You want me to implement it using the compatibility mode or to port it to GL 3+?

ndelb commented 9 years ago

You are right, I wrote it using the "old" OpenGL to keep it short (and so it works!). Il would be better to make an example that uses GL+ capabilities. If you want I could try to rewrite this example using oglplus and a GL 3+ context. But I have been having issue with that. Do I need an instance of oglplus::Context per window?

ndelb commented 9 years ago

Hi, I managed to get a working a working example. I have a simple class to display a triangle with a GL3+ context using oglplus. What is important is to call glfwMakeContextCurrent(window_i); before the instantiation of each triangle; where window_i is the window where you want the triangle to appear. I'll see if this helps me fix my larger program or if I have more issues. Here is the code for those interested:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;

#include <oglplus/all.hpp>
using namespace oglplus;

static void error_callback(int error, const char* description)
{
  fputs(description, stderr);
}
static void key_callback1(GLFWwindow* window1, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window1, GL_TRUE);
  else
  {
    cout << "Received key input from window 1:" << endl;
    cout << "   key:"<<key<<", scancode:"<<scancode<<", action:"<<action<<", mods:"<<mods<<endl;
  }
}
static void key_callback2(GLFWwindow* window2, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window2, GL_TRUE);
  else
  {
    cout << "Received key input from window 2:" << endl;
    cout << "   key:"<<key<<", scancode:"<<scancode<<", action:"<<action<<", mods:"<<mods<<endl;
  }
}

class Triangle
{
  private:
    Context gl;                 
    VertexShader vs;
    FragmentShader fs;
    Program prog;
    //VAO for the mesh (just 2 triangles)
    VertexArray triangles;
    //VBO for the vertices positions
    Buffer verts;
  public:
    Triangle(int type)
    {
      vs.Source(" \
          #version 330\n \
          in vec3 Position; \
          void main(void) \
          { \
            gl_Position = vec4(Position, 1.0); \
          } \
        ");
      vs.Compile();
      if(type==1) //red color
      {
        fs.Source(" \
              #version 330\n \
              out vec4 fragColor; \
              void main(void) \
              { \
                fragColor = vec4(1.0, 0.0, 0.0, 1.0); \
              } \
            ");
      }
      else //green color
      {
        fs.Source(" \
              #version 330\n \
              out vec4 fragColor; \
              void main(void) \
              { \
                fragColor = vec4(0.0, 1.0, 0.0, 1.0); \
              } \
            ");
      }
      fs.Compile();  
      prog.AttachShader(vs);
      prog.AttachShader(fs);
      prog.Link();          
      prog.Use();           
      triangles.Bind();                                                       
      GLfloat vertices1[9] = {                                                
        0.0f,  0.5f, 0.0f,                                                   
        0.5f, -0.5f, 0.0f,                                                   
        -0.5f, -0.5f, 0.0f
      };                                                                      
      verts.Bind(Buffer::Target::Array);                             
      Buffer::Data( Buffer::Target::Array, 9, vertices1);   
      VertexArrayAttrib(prog, "Position").Setup<GLfloat>(3).Enable();
      gl.ClearColor(0,0,0,0);                                                 
      gl.ClearDepth(1);                                                       
    }
    void display(int windowWidth, int windowHeight)
    {
      gl.Viewport(0,0,windowWidth,windowHeight);
      gl.Clear().ColorBuffer().DepthBuffer();
      verts.Bind(Buffer::Target::Array);                             
      gl.DrawArrays(PrimitiveType::TriangleStrip, 0, 4);
    }
};

int main(void)
{
  GLFWwindow* window1;
  GLFWwindow* window2;
  glfwSetErrorCallback(error_callback);
  if (!glfwInit())
    exit(EXIT_FAILURE);
  window1 = glfwCreateWindow(640, 480, "Window 1", NULL, NULL);
  window2 = glfwCreateWindow(640, 480, "Window 2", NULL, NULL);
  if (!window1 || !window2)
  {
    glfwTerminate();
    exit(EXIT_FAILURE);
  }
  glfwSetWindowPos  (window2, 641, 0);
  glfwSetKeyCallback(window1, key_callback1);
  glfwSetKeyCallback(window2, key_callback2);
  glfwMakeContextCurrent(window1);
  GLenum err = glewInit();                                            
  if (GLEW_OK != err) {                                                                   
    fprintf(stderr, "Glew init Error: %s\n", glewGetErrorString(err));
    return -1;                                                        
  }                                                                   
  glfwMakeContextCurrent(window1);
  Triangle triangle1(1);
  glfwMakeContextCurrent(window2);
  Triangle triangle2(2);
  bool running = true;
  while(running)
  {
    //check if windows should close
    if(glfwWindowShouldClose(window1))
      running = false;
    if(glfwWindowShouldClose(window2))
      running = false;
    //fist draw in window 1
    glfwMakeContextCurrent(window1);
    {
      int width, height;
      glfwGetFramebufferSize(window1, &width, &height);
      triangle1.display(width, height);
      glfwSwapBuffers(window1);
    }
    //then draw in window 2
    glfwMakeContextCurrent(window2);
    {
      int width, height;
      glfwGetFramebufferSize(window2, &width, &height);
      triangle2.display(width, height);
      glfwSwapBuffers(window2);
    }
    glfwPollEvents();
  }
  glfwDestroyWindow(window1);
  glfwDestroyWindow(window2);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}
matus-chochlik commented 9 years ago

Thanks, I'm going to have a look at it, probably during the wekend.