// engine includes
#include "app/Application.hpp"
#include "graphics/shaders/GLSLProgram.hpp"
#include "graphics/Mesh.hpp"
// std includes
#include <iostream>
#include <array>
// using namespaces for testing purposes-only
using namespace VAPE;
using namespace graphics;
using namespace camera;
// TimeStep global init. (provides time and deltaTime)
TimeStep time;
// the size of the meshes for the scene
constexpr size_t meshCount = 3;
// global resource objects
// to be added in the appplication class (this is just for example)
GLSLProgram basic;
std::array<std::shared_ptr<Mesh>, meshCount> meshes;
Let's #2. Setting up the main() function
setLoad(), setUpdate() and setRender() accept a lambda / std::function as an argument inside their bodies.
demo_scene.cpp
int main()
{
// instantiate a new application (window, input handlers, etc.)
Application app;
app.setLoad([&]() { load(); });
app.setUpdate([&](double deltaTime) { update(time.deltaTime); });
// the Renderer obj. is part of the Application obj.
app.setRender([&]() { render(app.renderer); });
// Run the application with the already set functions (above)
app.Run();
return EXIT_SUCCESS;
}
Let's #3. Define the load() function body
Its purpose is for initialization of shaders, meshes and resources in general.
demo_scene.cpp
void load()
{
// Compile shaders
basic.CompileShaderFile("Resources/Shaders/core.vert", GLSLShader::GLSLShaderType::VERTEX);
basic.CompileShaderFile("Resources/Shaders/core.frag", GLSLShader::GLSLShaderType::FRAGMENT);
// Build shader program. (link shaders). TODO: Add Exceptions to throw on errors.
basic.Build();
float span = 0.0f;
// Create meshes (cubes)
std::for_each(meshes.begin(), meshes.end(), [&](std::shared_ptr<Mesh> &mesh)
{
// Instantiate the mesh
mesh = std::make_shared<Mesh>();
// Transform the mesh
mesh->translate(glm::vec3(-1.5f + span, 0.0f, -10.0f));
mesh->rotate(glm::vec3(1.0f, 1.0f, glm::quarter_pi<float>()));
mesh->getScale() = glm::vec3(0.55f);
// TODO: Set Material, Set Shader !!!
// ... That can be done here as well, when materials get implemented.
span += 1.5f;
});
// Init camera
Application::cam.Init();
}
Let's #4. Define the update() function body
Its purpose is for updating the meshes' transform matrix in world and local coordinates.
demo_scene.cpp
void update(double deltaTime)
{
// e.g. rotate the cubes in 3D space
std::for_each(meshes.begin(), meshes.end(), [&](std::shared_ptr<Mesh> &mesh)
{
mesh->rotate(glm::vec3(1.0f, 1.0f, glm::quarter_pi<float>()));
});
}
Let's #5. Define the render() function body
Its purpose is for managing the current shader and the renderer queue.
demo_scene.cpp
void render(ForwardRenderer& renderer)
{
// Bind current shader
basic.Enable();
// Create renderer queue (allocated 1000 rend. commands)
renderer.Begin();
// Traverse the meshes
std::for_each(meshes.begin(), meshes.end(), [&](const std::shared_ptr<Mesh> &mesh)
{
if (!mesh) return;
// Get mesh transform
glm::mat4 M = mesh->GetTransformMatrix();
// Bind MVP matrix
basic.setUniform("projection", Application::cam.GetProj());
basic.setUniform("model_view", Application::cam.GetView() * M);
// Bind material
basic.setUniform("mat.emissive", glm::vec4(1.0f, .5f, 0.2f, 1.0f));
// Submit meshes in the renderer
renderer.SubmitMesh(mesh);
// Display everything submitted in the renderer
renderer.Present();
});
// Optimize renderer queue (batching, sorting...)
renderer.End();
}