#include #include #include #include "tangerine.h" 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(rg); 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, void* user_data = nullptr) { 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("tangerine example", uvec2(1600, 900)); if (rs) { if (!loadScene(rs)) { LOGF(Error, "error loading scene\n"); return 1; } doRenderLoop(rs, 60, render_cb_pre, nullptr, nullptr); freeRenderState(rs); return 0; } LOGF(Error, "error loading scene\n"); return 1; }