A small OpenGL 3+ renderer and game engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

349 lines
7.3 KiB

#include <cassert>
#include <cmath>
#include <glm/gtc/matrix_transform.hpp>
#include "tangerine.h"
using glm::vec3;
using glm::vec4;
using glm::uvec4;
using glm::mat4;
bool
loadLights(RenderState* rs)
{
LightsBuffer* lb = rs->lights_buf;
u32 idx = 0;
#if 0
// NOTE: add a directional light
idx = (*lb->active_d_lights)++;
lb->dl_directions[idx] = vec4(-2, 1, 3, 1);
lb->dl_colors[idx] = vec4(0.5, 0.5, 0.3, 1);
lb->dl_intensities[idx] = uvec4(1, 0, 0, 0);
#endif
// NOTE: add a point light
idx = (*lb->active_p_lights)++;
lb->pl_positions[idx] = vec4(-10, 0, -10, 1);
lb->pl_colors[idx] = vec4(1, 1, 0.8, 1);
lb->pl_intensities[idx] = vec4(3, 0, 0, 0);
GLBuffer* lights_ubo = getUBOByName(rs->gl_ctx, "lights");
assert(lights_ubo != nullptr);
updateGLBuffer(lights_ubo, lb->buffer);
// NOTE: add a debug mesh to view the point light source
RenderGroup* debug_group = getFreeRenderGroup(rs);
assert(debug_group);
ShaderProgram* s_debug = getShaderByName("debug", rs->gl_ctx);
assert(s_debug);
initRenderGroup(debug_group, rs->rg_arena, s_debug, 256, "debug_lights");
Entity* e = getFreeEntity(debug_group);
assert(e);
if (!initEntity(e,
rs->gl_ctx,
rs->rg_arena,
&rs->assets.models[0], // tex_cube from loadScene()
s_debug->num_vertex_attribs,
s_debug->attrib_mappings,
"debug_light"))
{
LOGF(Error, "Error initializing debug entity for light\n");
return false;
}
setEntityPosition(e, vec3(lb->pl_positions[idx]));
return true;
}
bool
loadCubes(RenderState* rs)
{
// NOTE: load model
Model* tex_cube = getModelByPath(&rs->assets, "../data/textured_cube.gltf");
if (!tex_cube) return false;
// NOTE: load new shader, or get one of the defaults
// NOTE: the default shaders already have their attribute mappings created
// in initRenderState, but if you use a custom shader, you will need to
// create a GLBufferToAttribMapping manually
ShaderProgram* shader_lit = getShaderByName("full_lighting", rs->gl_ctx);
if (!shader_lit) return false;
// NOTE: init new render group
RenderGroup* textured_cubes = getFreeRenderGroup(rs);
assert(textured_cubes);
initRenderGroup(textured_cubes, rs->rg_arena, shader_lit, 256,
"textured_cubes");
// NOTE: init entities
const u32 NUM_CUBES = 5;
vec3 cube_locs[NUM_CUBES] = {
vec3( 0, 0, 0),
vec3(-10, 10, 0),
vec3(-10, -10, 0),
vec3( 10, 10, 0),
vec3( 10, -10, 0),
};
for (u32 i = 0; i < NUM_CUBES; i++) {
Entity* e = getFreeEntity(textured_cubes);
assert(e);
char cube_name[256] = {0};
snprintf(cube_name, 256, "textured_cube%d", i);
if (!initEntity(e,
rs->gl_ctx,
rs->rg_arena,
tex_cube,
shader_lit->num_vertex_attribs,
shader_lit->attrib_mappings,
cube_name))
{
return false;
}
setEntityPosition(e, cube_locs[i]);
scaleEntity(e, 3);
}
return true;
}
// NOTE: test an entity with multiple meshes
bool
loadSpaceShip(RenderState* rs)
{
Model* ship = getModelByPath(&rs->assets, "../data/spaceship.gltf");
if (!ship)
return false;
ShaderProgram* shader_lit = getShaderByName("full_lighting", rs->gl_ctx);
if (!shader_lit)
return false;
// load model into gl
RenderGroup* rg = getFreeRenderGroup(rs);
assert(rs);
initRenderGroup(rg, rs->rg_arena, shader_lit, 256, "ships");
Entity* e = getFreeEntity(rg);
assert(e);
if (initEntity(e, rs->gl_ctx,
rs->rg_arena,
ship,
shader_lit->num_vertex_attribs,
shader_lit->attrib_mappings,
"ship 01"))
{
setEntityPosition(e, vec3(0, -10, -15));
} else {
return false;
}
return true;
}
bool
testColoredVertices(RenderState* rs)
{
Mesh m = {0};
m.num_vertices = 5;
m.num_indices = 12;
vec3 vertices[m.num_vertices] = {
{ 0, 1, 0 },
{ -1, -1, -1 },
{ -1, -1, 1 },
{ 1, -1, 0.5 },
};
u16 indices[m.num_indices] = {
0, 1, 2,
0, 2, 3,
0, 3, 1,
1, 2, 3
};
vec3 colors[m.num_vertices] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 },
{ 1, 1, 0 }
};
m.vertices = vertices;
m.colors = colors;
m.indices = indices;
mat4 xform = mat4(1);
m.xform = &xform;
Model mdl = {0};
mdl.num_meshes = 1;
mdl.meshes = &m;
ShaderProgram* shader = getShaderByName("colored_vertices", rs->gl_ctx);
RenderGroup* rg = getFreeRenderGroup(rs);
assert(shader && rg);
initRenderGroup(rg, rs->rg_arena, shader, 256, "colored_pyramids");
Entity* e = getFreeEntity(rg);
assert(e);
if (initEntity(e, rs->gl_ctx,
rs->rg_arena,
&mdl,
shader->num_vertex_attribs,
shader->attrib_mappings,
"colored pyramid 01"))
{
setEntityPosition(e, vec3(0, -10, 15));
} else {
return false;
}
return true;
}
bool
loadCamera(RenderState* rs)
{
Camera* cam = rs->camera;
vec3 cam_pos = { 0, 15, 40 };
vec3 look_pos = { 0, 0, 0 };
vec3 up = { 0, 1, 0 };
cameraInitPerspective(cam, cam_pos, look_pos, up);
GLBuffer* xforms_ubo = getUBOByName(rs->gl_ctx, "matrices");
if (!xforms_ubo)
return false;
updateGLBuffer(xforms_ubo, &cam->xforms);
return true;
}
bool
loadScene(RenderState* rs)
{
if (!loadCubes(rs)) {
LOGF(Error, "Error loading cubes\n");
return false;
}
if (!testColoredVertices(rs)) {
LOGF(Error, "Error loading colored vertices\n");
return false;
}
if (!loadSpaceShip(rs)) {
LOGF(Error, "Error loading ship modeln");
return false;
}
if (!loadCamera(rs)) {
LOGF(Error, "Error loading camera\n");
return false;
}
return loadLights(rs);
}
void
orbitPositionZ0(vec4* pos, float angle)
{
// get radius length
float r = sqrt(pow(abs(pos->x), 2) + pow(abs(pos->z), 2));
// get current angle about z axis
float a = atan2f(pos->z, pos->x);
// apply increment
a += angle;
// get new x/z components
pos->x = r * cos(a);
pos->z = r * sin(a);
}
void
render_cb_pre(RenderState* rs)
{
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT ||
(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE))
{
rs->running = false;
break;
}
}
// NOTE: orbit point light
LightsBuffer* lb = rs->lights_buf;
orbitPositionZ0(&lb->pl_positions[0], 2 * M_PI / 180);
RenderGroup* rg = getRenderGroupByName(rs, "debug_lights");
Entity* ent = &rg->entities[0];
setEntityPosition(ent, vec3(lb->pl_positions[0]));
GLBuffer* lights_ubo = getUBOByName(rs->gl_ctx, "lights");
assert(lights_ubo);
updateGLBuffer(lights_ubo, lb->buffer);
// NOTE: orbit camera
static vec4 cam_pos;
static vec3 look_pos;
static vec3 up;
static bool initialized = false;
if (!initialized) {
cam_pos = { 0, 15, 40, 1 };
look_pos = { 0, 0, 0 };
up = { 0, 1, 0 };
initialized = true;
}
orbitPositionZ0(&cam_pos, 0.5 * M_PI / 180);
rs->camera->xforms.view =
glm::lookAt(vec3(cam_pos), vec3(0, 0, 0), vec3(0, 1, 0));
static GLBuffer* xform_ubo = nullptr;
if (!xform_ubo) {
xform_ubo = getUBOByName(rs->gl_ctx, "matrices");
assert(xform_ubo != nullptr);
}
updateGLBuffer(xform_ubo, &rs->camera->xforms);
// NOTE: rotate cubes
RenderGroup* rg2 = getRenderGroupByName(rs, "textured_cubes");
for (u32 j = 0; j < rg2->num_entities; j++) {
Entity& e = rg2->entities[j];
float direction = (j % 2 == 0) ? 1 : -1;
rotateEntity(&e, vec3(0, 1, 0), direction * (float) M_PI / (3 * 60));
}
}
int
main()
{
RenderState* rs = initRenderState();
if (rs) {
if (!loadScene(rs)) {
LOGF(Error, "error loading scene\n");
return 1;
}
doRenderLoop(rs, 60, render_cb_pre, nullptr);
freeRenderState(rs);
return 0;
}
LOGF(Error, "error loading scene\n");
return 1;
}