
- Author
- Swarnava Ghosh
Introduction
GLider is an OpenGL class abstraction library. It uses glad to load the OpenGL functions, which can be customized using CMake.
Usage
To get the best idea on how to use this library, look at the code for rendering a triangle step by step:
Window Creation
Since window management is not part of the OpenGL specifications, this step is left to the user to accomplish. Good window managemenent libraries include GLFW and SDL
Acquire OpenGL Context
An OpenGL context must be acquired before initializing GLider. Since context creation is not part of OpenGL specifications, it is not part GLider. Normally, your window managerment library will provide functions to get this context.
// GLFW
glfwMakeContextCurrent(window);
// SDL
SDL_GL_CreateContext(window);
Initialize GLider
Once you have the OpenGL context, we can initiate GLider. If you have a function that retrives OpenGL functions, you can pass this as an argument. Again, that OpenGL function getter may be provided to you by your window managment library.
Shader Sources
const char* vertexShader = R"CODE(
#version 140
in vec4 vertexPos;
in vec3 vertexColor;
out vec3 fragmentColor;
void main(){
gl_Position = vertexPos;
fragmentColor = vertexColor;
}
)CODE";
const char* fragmentShader = R"CODE(
#version 140
in vec3 fragmentColor;
void main(){
gl_FragColor = vec4(fragmentColor, 1.f);
}
)CODE";
This is the OpenGL shader source code. You can define a string, or you can write it in a seperate file.
Glider Variable Declarations
Definition: Buffer.hpp:63
Definition: ShaderProgram.hpp:59
Definition: VertexArray.hpp:30
Declares variables using GLider classes
Vertex Data
std::array<float, 5*3> vertecies = {
-.75, -.75, 1.f, 0.f, 0.f,
0, .75, 0.f, 1.f, 0.f,
.75, -.75, 0.f, 0.f, 1.f
};
Vertex data can be specified using any C++ standard container, as long as the containers have data()
and size()
member functions.
Storing Vertex Data in VRAM
{
vb,
layout
);
}
void feedData(const T *data, unsigned int dataCount, BufferUsage usage)
Definition: VertexArray.hpp:14
void push(Dimensions count, bool normalized)
void readBufferData(const Buffer< VertexBuffer > &vb, const Layout &layout, unsigned int startingAttribIndex=0)
@ D3
Definition: VertexArray.hpp:11
@ D2
Definition: VertexArray.hpp:11
@ UseDynamicDraw
Definition: Buffer.hpp:48
These lines are responsible for feeding the vertex data to OpenGL and telling it how to interpret the data. The first thing that needs to be done is to feed the data into a vertex buffer (through a gli::Buffer<gli::VertexBuffer> object). Once that is done, a vertex array is supposed to read and make sense of the data. For this, we need to specify the structure of the data using an array (or vector) of gli::LayoutElement objects.
Vertex Attribute Locations
void bindAttribLocation(unsigned int index, const char *name) const noexcept
We need to specify the appropriate vertex attribute locations so that the shader can find those attributes. This step is not necessary if you decide to use the layout
qualifier within your shader source code.
Shader Compilation
void compileString(ShaderType shaderType, const char *sourceCode)
A lot of the OpenGL shader compilation procedures are automated through GLider. If you wrote your source code in a seperate file, you can use gli::ShaderProgram::compileFile(ShaderType, const char*) instead of gli::ShaderProgram::compileString(ShaderType, const char*).
Binding
va.bind();
shaders.bind();
These lines just ensure that the correct objects are bound for OpenGl to read from.
Render Loop
void draw(DrawType mode, int first, int count) const noexcept
void clear(BufferBit mask) noexcept
@ DepthBufferBit
Definition: OpenGLBase.hpp:117
@ ColorBufferBit
Definition: OpenGLBase.hpp:116
@ DrawTriangles
Definition: OpenGLBase.hpp:103
Once all the variables are set, we can loop through this piece of code to render triangle. It clears the color and depth buffers, and draws the shape described by the data we spent so long organizing for OpenGL.
Swap
To actually update the contents of the screen, we must update the view buffer. This is not part of OpenGL specifications, and thus is left out of GLider. Your window management library should have some feature to swap the buffers.
glfwSwapBuffers(window);
SDL_GL_SwapWindow(window);
Event Handling
In the main render loop, after the drawing and swapping, comes your event handling code, which is again not the concern of OpenGL.
Everything Together
The following code does exactly what the above section does, with SDL as the window management library. Note that there is a seperate piece of helper code outside of view that makes managing SDL easier.
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include "util.hpp"
const char* vertexShader = R"CODE(
#version 140
in vec4 vertexPos;
in vec3 vertexColor;
out vec3 fragmentColor;
void main(){
gl_Position = vertexPos;
fragmentColor = vertexColor;
}
)CODE";
const char* fragmentShader = R"CODE(
#version 140
in vec3 fragmentColor;
void main(){
gl_FragColor = vec4(fragmentColor, 1.f);
}
)CODE";
int main(
int argc,
char* argv[]){
float openDuration_ms = 0.f;
auto start = std::chrono::steady_clock::now();
if(argc >= 2) openDuration_ms = std::atof(argv[1]);
try{
SDL sdl(3,0);
SDL_DisplayMode dm;
if (SDL_GetDesktopDisplayMode(0, &dm) != 0)
throw std::runtime_error(SDL_GetError());
SDL::OpenGLWindow win{"Triangle", (dm.w*3)/4, (dm.h*3)/4};
std::array<float, 5*3> vertecies = {
-.75, -.75, 1.f, 0.f, 0.f,
0, .75, 0.f, 1.f, 0.f,
.75, -.75, 0.f, 0.f, 1.f
};
{
vb,
layout
);
}
va.bind();
shaders.bind();
bool keepRunning = true;
SDL_Event e;
while(keepRunning){
win.swap();
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
keepRunning = false;
break;
case SDL_KEYDOWN:
switch(e.key.keysym.sym){
case SDLK_ESCAPE:
if(e.key.keysym.mod & KMOD_SHIFT)
keepRunning = false;
break;
}
break;
}
}
if(openDuration_ms > 0.f){
if(
std::chrono::duration_cast<std::chrono::duration<float, std::milli>>
(std::chrono::steady_clock::now() - start).count() >= openDuration_ms
)
keepRunning = false;
}
}
}catch(std::exception& e){
std::printf("Error Occured: %s\n", typeid(e).name());
std::printf("%s", e.what());
}
return 0;
}
Main header file for GLider which includes all other header files.
int main()
Definition: init.dox:3