This should be a really obvious answer and somewhere I've probably mucked up a line or two, and yet I can't seem to get triangles to draw to a framebuffer.
What I'm trying to do is get two triangles to a large render buffer object, with a framebuffer attached, and then in one of four windows display a slice of the larger render buffer/framebuffer using glBlitFramebuffer.
I'm using init_FB()
to define the triangles to render and the RBO in which to render those triangles. I've created a renderbuffer object and a framebuffer object associated with the renderbuffer object. In the compute_FB()
function I am binding the framebuffer of the RBO and then making a call to draw into that framebuffer. Before drawing the triangles, I am clearing the framebuffer to a specific color, royalblue
.
In the first window, called window
, what's appearing is only the color royalblue
defined by the function (compute_FB()
) that draws into the framebuffer of the renderbuffer object. However, none of the triangles are being drawn eventhough I have a glDrawArrays(...)
function being called at the end of compute_FB()
.
I'm beginning to believe that the RBO needs its own context in which to render successfully, but I don't know how to set up a context for a RBO. I thought contexts were only for windows in GLFW.
I am basing my attempt on the initial OpenGL Redbook example 01-triangles. In this example I've coded four unique windows and want eventually to copy a large RBO/framebuffer to each of the four windows - currently I'm just focusing on the first display.
I am using OpenGL4.5 with GLFW for windowing.
//////////////////////////////////////////////////////////////////////////////
//
// Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include "vgl.h"
#include "LoadShaders.h"
#include <vector>
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
//////////////////////////////////////////////////
// Framebuffer Variables
//////////////////////////////////////////////////
enum {Color, NumRenderBuffers};
GLuint framebuffer, renderbuffer[NumRenderBuffers];
GLuint fbwidth = 3200;
GLuint fbheight = 600;
//----------------------------------------------------------------------------
//
// init
//
void init_FB( void )
{
// Create an Empty RenderBuffer and Associated Framebuffer
glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, fbwidth, fbheight);
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glNamedFramebufferRenderbuffer(framebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
glEnable(GL_DEPTH_TEST);
// Here's some info to initialize for the RBO
// The framebuffer for the RBO has been bound (above) and ?SHOULD? be ready to draw to, right?
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -1.00f, -1.00f }, { -1.00f, 0.40f }, { 0.00f, -1.00f }, // Triangle 1
{ 0.00f, 0.40f }, { 0.40f, 0.40f }, { 0.40f, -0.40f } // Triangle 2
};
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void init( void )
{
// Create the standard window framebuffer for this window context
// Basically, I want to give the window a framebuffer so that I can draw into it later in the 'draw' phase
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
static const float black[] = { 1.0f, 0.5f, 0.2f, 0.0f };
// May as well clear it to a color that's visually separate from the color that it will be cleared to
// .. in the draw phase.
glClearBufferfv(GL_COLOR, 0, black);
}
void init2( void )
{
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.60f }, { -0.85f, -0.60f }, { -0.50f, -0.65f }, // Triangle 1
{ 0.90f, -0.85f }, { 0.90f, 0.90f }, { -0.85f, 0.90f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void init3( void )
{
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f }, { -0.90f, 0.90f }, { 0.00f, -0.90f }, // Triangle 1
{ 0.00f, 0.90f }, { 0.90f, 0.90f }, { 0.90f, -0.90f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void init4( void )
{
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.40f, -0.40f }, { -0.40f, 0.40f }, { 0.00f, -0.40f }, // Triangle 1
{ 0.00f, 0.40f }, { 0.40f, 0.40f }, { 0.40f, -0.40f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
//----------------------------------------------------------------------------
//
// display
//
void compute_FB()
{
// Prepare to render into the framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glViewport(0, 0, fbwidth, fbheight);
// Clear before drawing. This shade of color comes through to the first window display
static const float black[] = { 0.0f, 0.3f, 0.8f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
// Try drawing the triangles... Nuthin
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
// Read from a section of the RBO/framebuffer
void display( void )
{
static const float black[] = { 0.8f, 0.0f, 0.0f, 0.0f };
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); // Set framebuffer to read from
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // set window to draw to
glViewport(0, 0, 800, 600); // Probbaly not needed
// Copy from READ framebuffer to DRAW framebuffer
// QUESTION: Why isn't this copying to just a small corner of the window context's framebuffer?
glBlitFramebuffer(0, 0, fbwidth, fbheight, 0, 0, 100, 200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
void display2( void )
{
static const float black[] = { 0.0f, 0.3f, 0.4f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
void display3( void )
{
static const float black[] = { 0.7f, 0.6f, 0.4f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
void display4( void )
{
static const float black[] = { 0.2f, 0.3f, 0.7f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
//
// main
//
#ifdef _WIN32
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
// Initialize GLFW
glfwInit();
//TODO Create Windows Class
// Create Windows
GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, NULL);
GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, NULL);
GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, NULL);
// Initialize OpenGL
gl3wInit();
// Framebuffer Initialization
init_FB();
// Initialize Windows
glfwMakeContextCurrent(window);
init();
glfwMakeContextCurrent(window2);
init2();
glfwMakeContextCurrent(window3);
init3();
glfwMakeContextCurrent(window4);
init4();
// Draw the Windows
while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
{
glfwMakeContextCurrent(window);
compute_FB();
display();
glfwSwapBuffers(window);
glfwPollEvents();
glfwMakeContextCurrent(window2);
display2();
glfwSwapBuffers(window2);
glfwPollEvents();
glfwMakeContextCurrent(window3);
display3();
glfwSwapBuffers(window3);
glfwPollEvents();
glfwMakeContextCurrent(window4);
display4();
glfwSwapBuffers(window4);
glfwPollEvents();
}
// Destroy Windows
glfwDestroyWindow(window);
glfwDestroyWindow(window2);
glfwDestroyWindow(window3);
glfwDestroyWindow(window4);
// Terminate GLFW Instance
glfwTerminate();
}
Thanks to @Ripi2, I am now able to use glBlit and a renderbuffer. Somehow though I am not correctly using either or both of the renderbuffer and different FBO for the second window. NOTE At this point, I am not yet implementing the glBlit on the third or fourth windows (though I will, once I can succesfully integrate the renderbuffer and glBlit into the second window)
Edit #2 Code
//////////////////////////////////////////////////////////////////////////////
//
// Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include <cstdio>
#include "vgl.h"
#include "LoadShaders.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
////////////////////////////////////
//RBO variables
enum {Color=0, NumRenderBuffers=1, NumFBOs=4};
GLuint renderbuffer[NumRenderBuffers], fbos[NumFBOs];
GLuint buffwidth = 3200;
GLuint buffheight = 600;
//----------------------------------------------------------------------------
//
// init
//
void
init( void )
{
glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, buffwidth, buffheight);
glGenFramebuffers(1, &fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
glNamedFramebufferRenderbuffer(fbos[0], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f }, { -0.90f, 0.90f }, { 0.00f, -0.90f }, // Triangle 1
{ 0.00f, 0.90f }, { 0.90f, 0.90f }, { 0.90f, -0.90f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void
init2( void )
{
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
glGenFramebuffers(1, &fbos[1]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
glNamedFramebufferRenderbuffer(fbos[1], GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderbuffer[Color]);
}
void
init3( void )
{
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f }, { -0.90f, 0.90f }, { 0.00f, -0.90f }, // Triangle 1
{ 0.00f, 0.90f }, { 0.90f, 0.90f }, { 0.90f, -0.90f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void
init4( void )
{
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.40f, -0.40f }, { -0.40f, 0.40f }, { 0.00f, -0.40f }, // Triangle 1
{ 0.00f, 0.40f }, { 0.40f, 0.40f }, { 0.40f, -0.40f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
//----------------------------------------------------------------------------
//
// display
//
void
display( void )
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
glViewport(0, 0, buffwidth, buffheight);
static const float black[] = { 0.2f, 0.2f, 0.2f, 0.0f };
static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, 800, 600);
glClearBufferfv(GL_COLOR, 0, redish);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
void
display2( void )
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[1]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, 800, 600);
static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
glClearBufferfv(GL_COLOR, 0, redish);
glBlitFramebuffer(buffwidth, 0, buffwidth+800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
void
display3( void )
{
static const float black[] = { 0.7f, 0.6f, 0.4f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
void
display4( void )
{
static const float black[] = { 0.2f, 0.3f, 0.7f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
//
// main
//
#ifdef _WIN32
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
// Initialize GLFW
glfwInit();
// Initialize OpenGL
// Place it here before any OpenGL objects are needed, other OpenGL crashes
// ... in a "Segmentation fault (core dumped)" error
gl3wInit();
//TODO Create Windows Class
// Create Windows
GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, window);
GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, window);
GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, window);
// Initialize Windows
glfwMakeContextCurrent(window);
init();
glfwMakeContextCurrent(window2);
init2();
glfwMakeContextCurrent(window3);
init3();
glfwMakeContextCurrent(window4);
init4();
// Draw the Windows
while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
{
glfwMakeContextCurrent(window);
display();
glfwSwapBuffers(window);
glfwPollEvents();
glfwMakeContextCurrent(window2);
display2();
glfwSwapBuffers(window2);
glfwPollEvents();
glfwMakeContextCurrent(window3);
display3();
glfwSwapBuffers(window3);
glfwPollEvents();
glfwMakeContextCurrent(window4);
display4();
glfwSwapBuffers(window4);
glfwPollEvents();
}
// Destroy Windows
glfwDestroyWindow(window);
glfwDestroyWindow(window2);
glfwDestroyWindow(window3);
glfwDestroyWindow(window4);
// Terminate GLFW Instance
glfwTerminate();
}
Notes
glBlit
copies to each active window. This may have worked, but upon guidance I was talked down to performing the actual rendering in the main window and then copying into the final three windows. This is faster because there are less operationsglfwCreateWindow();
command is a parameter in which to pass the context from another window. Since I was creating the renderbuffer in the initial init()
for the first window, I had to set window
for the final param for all three other windows, like so: GLFWwindow *window2 = glfwCreateWindow(width, height, title, NULL, window-whose-context-i-want-to-share);
init
functions created a framebuffer and binds the renderbuffer to the current context.display()
function. In other words, while the rendered data will still exist, you won't have access to it until you bind it in your current context... everytime you change to rendering into a new window.init2(const int)
is the command that binds the current context's framebuffer to the shared renderbuffer, glNamedFramebufferRenderbuffer(...)
, must have the same renderbuffer-target as the original renderbuffer-target defined in init()
: GL_COLOR_ATTACHMENT0
. In hindsight, this should have been obvious, but the amount of documentation for multi-window rendering from a renderbuffer object was hard to find. Almost all others gave demonstrations using glTexture objects instead of renderbuffers. This GL_COLOR_ATTACHMENTi
is like an internal address where multiple sets of rendered data can be stored... a very good hint for future projects.display2(const int)
function, the important thing to set here was that the framebuffer was only going to READ from the renderbuffer, so use GL_READ_FRAMEBUFFER
- because the data is already there and we're just using a framebuffer object as a way to get access to the data inside the renderbuffer. The FBO is the conduit, instead of the storage. Indeed, there is no way to access the data inside a renderbuffer without attaching an FBO first.glGet
function family in order to get information about the renderbuffer in different contexts, as well as the framebuffer. When the results from the gets matched my expectations, I knew I was on the right track. You'll see in display2(const int)
that I left two lines in that get a renderbuffer parameter: the width. I left it in this code snippet for anyone else who might be interested in how this would work. WARNING printing from a display
function is a bad idea for anything other than rudimentary debugging, because it will write the console once per cycle - and writing to stdout is ridiculously slow.//////////////////////////////////////////////////////////////////////////////
//
// Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include <cstdio>
#include "vgl.h"
#include "LoadShaders.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
////////////////////////////////////
//RBO variables
enum {Color=0, NumRenderBuffers=1, NumFBOs=4};
GLuint renderbuffer[NumRenderBuffers], fbos[NumFBOs];
GLuint buffwidth = 3200;
GLuint buffheight = 600;
//----------------------------------------------------------------------------
//
// init
//
void
init( void )
{
glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, buffwidth, buffheight);
glGenFramebuffers(1, &fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
glNamedFramebufferRenderbuffer(fbos[0], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
printf("\"init()\", is RB valid: %i\n", glIsRenderbuffer(renderbuffer[Color]));
printf("\"init()\", is FBO valid: %i\n", glCheckNamedFramebufferStatus(fbos[0], GL_DRAW_FRAMEBUFFER));
glGenVertexArrays( NumVAOs, VAOs );
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f }, { -0.90f, 0.90f }, { 0.00f, -0.90f }, // Triangle 1
{ 0.00f, 0.90f }, { 0.90f, 0.90f }, { 0.90f, -0.90f } // Triangle 2
};
glCreateBuffers( NumBuffers, Buffers );
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
glVertexAttribPointer( vPosition, 2, GL_FLOAT,
GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void
init2( const int idx_in )
{
glGenFramebuffers(1, &fbos[idx_in]);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[idx_in]);
glEnable(GL_RENDERBUFFER);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
GLint tmpwidth = 0;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &tmpwidth);
glNamedFramebufferRenderbuffer(fbos[idx_in], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
printf("\"init2()\", RB width is: %i\n", tmpwidth);
printf("\"init2()\", is RB valid: %i\n", glIsRenderbuffer(renderbuffer[Color]));
printf("\"init2()\", is FBO valid: %i\n", glCheckNamedFramebufferStatus(fbos[idx_in], GL_DRAW_FRAMEBUFFER));
}
//----------------------------------------------------------------------------
//
// display
//
void
display( void )
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
glViewport(0, 0, buffwidth, buffheight);
static const float black[] = { 0.2f, 0.2f, 0.2f, 0.0f };
static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
glClearBufferfv(GL_COLOR, 0, black);
glBindVertexArray( VAOs[Triangles] );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, 800, 600);
glClearBufferfv(GL_COLOR, 0, redish);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
void
display2( const int idx_in )
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[idx_in]);
GLint tmpwidth = 0;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &tmpwidth);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, 800, 600);
glBlitFramebuffer(800 * idx_in - 1, 0, 800 * idx_in - 1 + 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
//----------------------------------------------------------------------------
//
// main
//
#ifdef _WIN32
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
// Initialize GLFW
glfwInit();
//TODO Create Windows Class
// Create Window Hints
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
// Create Windows
GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, window);
GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, window);
GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, window);
// Set window positions
glfwSetWindowPos(window, 100, 100);
glfwSetWindowPos(window2, 900, 100);
glfwSetWindowPos(window3, 1700, 100);
glfwSetWindowPos(window4, 2500, 100);
// Initialize Windows
glfwMakeContextCurrent(window);
// Initialize gl3w - thanks @Ripi2 for the assist
gl3wInit();
init();
glfwMakeContextCurrent(window2);
init2(1);
glfwMakeContextCurrent(window3);
init2(2);
glfwMakeContextCurrent(window4);
init2(3);
// Draw the Windows
while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
{
glfwMakeContextCurrent(window);
display();
glfwSwapBuffers(window);
glfwPollEvents();
glFinish();
glfwMakeContextCurrent(window2);
display2(1);
glfwSwapBuffers(window2);
glfwPollEvents();
glFinish();
glfwMakeContextCurrent(window3);
display2(2);
glfwSwapBuffers(window3);
glfwPollEvents();
glfwMakeContextCurrent(window4);
display2(3);
glfwSwapBuffers(window4);
glfwPollEvents();
}
// Destroy Windows
glfwDestroyWindow(window);
glfwDestroyWindow(window2);
glfwDestroyWindow(window3);
glfwDestroyWindow(window4);
// Terminate GLFW Instance
glfwTerminate();
}