VVISF & VVGL
Sample Code VII- GLScene

VVGL::GLScene is a frontend for a performing custom render commands in an OpenGL context. It's a relatively simple class- it lets you provide a block that executes drawing commands and performs a series of rendering steps that can be customized, with built-in support for orthogonal rendering, rendering to textures/GLBufferRef, and support for a variety of different versions of OpenGL.

Following are some examples that demonstrate creating and configuring a GLScene, and then rendering it into a texture.


Creating and GLScene and rendering it to a texture for older versions of GL:

// make the shared context, set up the global buffer pool to use it
CreateGlobalBufferPool(sharedContext);
// you can create a scene around an existing context or- as shown here- make a new context for the scene
// configure the scene's render callback
glScene->setRenderCallback([](const GLScene & inScene) {
// populate a tex quad with the geometry, tex, and color vals- this struct is organized in a manner compatible with GL such that it's both easy to work with and can be uploaded directly.
Quad<VertXYZRGBA> texQuad;
VVGL::Size sceneSize = inScene.orthoSize();
texQuad.populateGeo(VVGL::Rect(0,0,sceneSize.width,sceneSize.height));
texQuad.bl.color = GLColor(1., 1., 1., 1.);
texQuad.tl.color = GLColor(1., 0., 0., 1.);
texQuad.tr.color = GLColor(0., 1., 0., 1.);
texQuad.br.color = GLColor(0., 0., 1., 1.);
// configure GL to expect vertex and color coords when it draws.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// set the pointers to the vertex and color coords
glVertexPointer(texQuad.bl.geo.numComponents(), GL_FLOAT, texQuad.stride(), &texQuad.bl.geo[0]);
glColorPointer(texQuad.bl.color.numComponents(), GL_FLOAT, texQuad.stride(), &texQuad.bl.color[0]);
// draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
});
// create a GLBuffer for an OpenGL texture, render the scene to it
GLBufferRef renderedTexture = CreateRGBATex(VVGL::Size(1920,1080));
glScene->renderToBuffer(renderedTexture);


Creating a GLScene and rendering it to a texture for desktop GL 3+:

// make the shared context, set up the global buffer pool to use it
CreateGlobalBufferPool(sharedContext);
// you can create a scene around an existing context or- as shown here- make a new context for the scene
// create the vertex & fragment shaders, tell the scene to use them
string vsString("\r\
#version 330 core\r\
in vec3 inXYZ;\r\
in vec4 inRGBA;\r\
uniform mat4 vvglOrthoProj;\r\
out vec4 programRGBA;\r\
void main() {\r\
gl_Position = vec4(inXYZ.x, inXYZ.y, inXYZ.z, 1.0) * vvglOrthoProj;\r\
programRGBA = inRGBA;\r\
}\r\
");
string fsString("\r\
#version 330 core\r\
in vec4 programRGBA;\r\
out vec4 FragColor;\r\
void main() {\r\
FragColor = programRGBA;\r\
}\r\
");
glScene->setVertexShaderString(vsString);
glScene->setFragmentShaderString(fsString);
// we're going to create a VAO, we also need attribs for the XYZ and RGBA inputs, and quad to store the last-uploaded data
static GLBufferRef vao = nullptr;
static GLCachedAttribRef xyzAttr = make_shared<GLCachedAttrib>("inXYZ");
static GLCachedAttribRef rgbaAttr = make_shared<GLCachedAttrib>("inRGBA");
static Quad<VertXYZRGBA> vboData = Quad<VertXYZRGBA>();
// configure the scene's render prep callback to cache the location of the vertex attributes and uniforms
glScene->setRenderPrepCallback([](const GLScene & inScene, const bool & inReshaped, const bool & inPgmChanged) {
if (inPgmChanged) {
// cache all the locations for the vertex attributes & uniform locations
GLint myProgram = inScene.program();
xyzAttr->cacheTheLoc(myProgram);
rgbaAttr->cacheTheLoc(myProgram);
// make a new VAO
vao = CreateVAO(true);
}
});
// configure the scene's render callback to pass the data to the GL program if it's changed (the params to targetQuad were animated, but i took it out because it wasn't x-platform)
glScene->setRenderCallback([](const GLScene & inScene) {
VVGL::Size orthoSize = inScene.orthoSize();
VVGL::Rect boundsRect(0, 0, orthoSize.width, orthoSize.height);
Quad<VertXYZRGBA> targetQuad;
targetQuad.populateGeo(boundsRect);
targetQuad.bl.color = GLColor(1., 1., 1., 1.);
targetQuad.tl.color = GLColor(1., 0., 0., 1.);
targetQuad.tr.color = GLColor(0., 1., 0., 1.);
targetQuad.br.color = GLColor(0., 0., 1., 1.);
// bind the VAO
glBindVertexArray(vao->name);
uint32_t vbo = 0;
// if the target quad differs from the vbo data, there's been a change/animation and we need to push new data to the GL program
if (vboData != targetQuad) {
vboData = targetQuad;
// make a new VBO to contain vertex + color data
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(targetQuad), (void*)(&targetQuad), GL_STATIC_DRAW);
// configure the attribute pointers to use the VBO
if (xyzAttr->loc >= 0) {
glVertexAttribPointer(xyzAttr->loc, targetQuad.bl.geo.numComponents(), GL_FLOAT, GL_FALSE, targetQuad.stride(), BUFFER_OFFSET(targetQuad.geoOffset()));
xyzAttr->enable();
}
if (rgbaAttr->loc >= 0) {
glVertexAttribPointer(rgbaAttr->loc, targetQuad.bl.color.numComponents(), GL_FLOAT, GL_FALSE, targetQuad.stride(), BUFFER_OFFSET(targetQuad.colorOffset()));
rgbaAttr->enable();
}
}
// draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// un-bind the VAO
glBindVertexArray(0);
// if we created a vbo earlier, delete it now (the vao will retain it)
if (vbo != 0) {
glDeleteBuffers(1, &vbo);
}
});
// create a GLBuffer for an OpenGL texture, render the scene to it
GLBufferRef renderedTexture = CreateRGBATex(VVGL::Size(1920,1080));
glScene->renderToBuffer(renderedTexture);