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
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; |
|
} |
|
|
|
|