Set enviorement
To make it simple I'm going to use sokol app.
sapp_desc sokol_main(int argc, char **argv)
{
sapp_desc app = {};
app.width = gWindowWidth;
app.height = gWindowHeight;
app.frame_cb = onFrame;
app.init_cb = onInit;
app.cleanup_cb = onEnd;
// app.win32_console_create = true;
app.win32_console_attach = true;
return app;
}
On Init
When we star the program, we are going to load gladGL, init the shaders, upload the mesh & configurate the triangles draw.
static float gRawMesh0[3 * 3] = {
-0.86f, -0.49f, 0.0f,
0.0f, 1.0f, 0.0f,
0.86f, -0.49f, 0.0f,
};
static unsigned int gIndices[3] = {
// note that we start from 0!
0, 1, 2,
};
static unsigned int gVBO0 = 0, gVAO0 = 0, gEBO0 = 0;
void onInit()
{
gladLoadGL();
stm_setup(); // Init time libreria SOKOL
// Shaders
char *vertex_shader_source = (char *)ReadSrcCode("vertex.glslv");
char *fragment_shader_source = (char *)ReadSrcCode("fragment.glslf");
ShadersInit(gShaderProgram, vertex_shader_source, fragment_shader_source);
// Custom own function
UploadMesh(gRawMesh0, sizeof(gRawMesh0), gIndices, sizeof(gIndices),
gVBO0, gVAO0, gEBO0);
// Triangles draw configuration
glDisable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
// Uniforms
gLocationColor = glGetUniformLocation(gShaderProgram, "RawColor");
}
Upload Mesh function
Here we Upload a mesh object that has a vertex array and a index array.
static void UploadMesh(float *mesh, int mesh_size,
unsigned int *indices, int indices_size,
unsigned int &VBO, unsigned int &VAO, unsigned int &EBO)
{
// Generamos 2 instancias de objetos OGL: array y buffer (sin inicializar)
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// Enfocamos ambos objetos, VAO y VBO
// Esto es recomendable, sino podriamos tocar atributos de VBOs y
// VAOs usados anteriormente
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
/*
Configuramos el buffer (tipo y cantidad de memoria).
EN ESTE MOMENTO SE COPIAN LOS VERTICES
STATIC_DRAW significa que los datos no se modificaran en el futuro
*/
glBufferData(GL_ARRAY_BUFFER, mesh_size, mesh, GL_STATIC_DRAW);
// Idem para los indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size, indices, GL_STATIC_DRAW);
/*
Configuramos el array describiendo los atributos de la estructura
(posicion, normal, uv, etc)
Es un array de vertices de 3 floats, con una separacion entre ellos de 12 bytes
El indice de attributo 0 se refiere normalmente a vertices (X,Y,X),
el 1 a normales (X,Y,Z) y el 2 a coord. textura (U,V). Pero no esta recomendado
usarlos asi, sino con (ej,) glGetAttribLocation(program, "position")
Ademas, glVertexAttribPointer relacion el buffer con este array por el ultimo "bind"
*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
/*
Se quita el foco del VAO y el VBO; glVertexAttribPointer ya se ha
quedado las referencias.
Quitar el foco evita que otras llamadas puedan modificar estos
objetos accidentalmente.
(No se debe quitar el foco del EBO mientras el VAO este en foco,
o perdera la referencia)
*/
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
On Frame
To make it simple I'm going to use sokol app.
static unsigned int gShaderProgram = 0;
static int gLocationColor = 0;
void onFrame()
{
gWindowWidth = sapp_width();
gWindowHeight = sapp_height();
double time = stm_ms(stm_now());
// Transformaciones de objeto y perspectiva (la camara se supone fija mirando a Z)
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 projection = glm::mat4(1.0f);
// Ponemos nuestra triangulo frente a la camara
model = glm::translate(model, glm::vec3(0.0f, 0.0f, -4.0f));
model = glm::rotate(model, 0.001f * (float)time, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, 0.002f * (float)time, glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, 0.003f * (float)time, glm::vec3(0.0f, 0.0f, 1.0f));
// Proyeccion con un FOV de 45 grados
projection = glm::perspective(glm::radians(45.0f),
((float)gWindowWidth) / (float)gWindowHeight, 0.1f, 100.0f);
// Render
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(gShaderProgram);
glUniform4f(gLocationColor, 1.0f, 0.4f, 1.0f, 1.0f);
// Obtenemos los identificadores (location) de los "uniform" de los shaders
unsigned int modelLoc = glGetUniformLocation(gShaderProgram, "model");
unsigned int projLoc = glGetUniformLocation(gShaderProgram, "projection");
// ...y enviamos las matrices a los shaders
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, &model[0][0]);
glUniformMatrix4fv(projLoc, 1, GL_FALSE, &projection[0][0]);
glBindVertexArray(gVAO0);
// Draw elements dibuja primitivas indexadas (en nuestros caso,
// mallas de triangulos)
glDrawElements(GL_TRIANGLES, sizeof(gIndices) / sizeof(unsigned int),
GL_UNSIGNED_INT, 0);
}
On End
Here we need to free the memory if we don't want any memory leak. We free the buffers and the shader program.
void onEnd()
{
glDeleteVertexArrays(1, &gVAO0);
glDeleteBuffers(1, &gVBO0);
glDeleteBuffers(1, &gEBO0);
glDeleteProgram(gShaderProgram);
}