#include "renderer.h" #include "../util/util_time.h" #include "../util/util.h" #include #define MAX_LIGHTS 4 Renderer render; void Render_Init(Window *window) { memset( &render, 0, sizeof(Renderer) ); if(glewInit() != GLEW_OK) Util_FatalError("Glew could no be started!"); strcpy( render.info.version, (const char *) glGetString(GL_VERSION) ); strcpy( render.info.vendor, (const char *) glGetString(GL_VENDOR) ); strcpy( render.info.shading_version, (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION) ); fprintf(stderr, "%s\n", render.info.version); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glClearColor(0.0f, 0.0f, 0.39f, 1.0f); //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); render.default_quad = mesh_make_quad(); render.default_shader = shader_new("pass_shader", "resources/shaders/passShader.vert", "resources/shaders/passShader.frag"); render.default_shader->totalTransform = shader_get_uniform_location(render.default_shader, "M_MVP"); render.default_shader->Texture = shader_get_uniform_location(render.default_shader, "Texture"); glBindVertexArray(render.default_quad->vao); glCreateBuffers(1, &render.instance_vbo); glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18 * 10000, NULL, GL_STREAM_DRAW); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 0)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 2) ); glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 6) ); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 10) ); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 18 * sizeof(GLfloat), (const void *)(sizeof(float) * 14) ); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glVertexAttribDivisor(1, 1); glVertexAttribDivisor(2, 1); glVertexAttribDivisor(3, 1); glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glBindVertexArray(0); render.window = window; render.shadow_width = 1024; render.shadow_height = 1024; /** TEMP **/ Vec3 center = {0.0f, 0.0f, 0.0f}; Vec3 up = {0.0f, 1.0f, 0.0f}; render.inv_light_dir = (Vec3){11.54f, 66.74f, 9.93f}; Mat4 shadow_ortho_mat = mat4_orthographic(-100.0f, 100.0f, -100.0f, 100.0f, -100.0f, 200.0f); Mat4 shadow_view_mat = mat4_lookAt(&render.inv_light_dir, ¢er, &up); Mat4 shadow_model; mat4_identity(&shadow_model); render.shadow_mvp = mat4_mul(&shadow_ortho_mat, &shadow_view_mat); render.shadow_mvp = mat4_mul(&render.shadow_mvp, &shadow_model); render.shadow_shader = shader_new("s_shader", "resources/shaders/shadow_shader.vert", "resources/shaders/shadow_shader.frag"); render.shadow_shader->totalTransform = shader_get_uniform_location(render.shadow_shader, "M_MVP"); /** TEMP **/ glGenFramebuffers(1, &render.shadow_fbo); glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo); glGenTextures(1, &render.shadow_map); glBindTexture(GL_TEXTURE_2D, render.shadow_map); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, render.shadow_width, render.shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenTextures(1, &render.shadow_color); glBindTexture(GL_TEXTURE_2D, render.shadow_color); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, render.shadow_width, render.shadow_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, render.shadow_map, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, render.shadow_color, 0); //glDrawBuffer(GL_NONE); GLenum draw_buffer = GL_COLOR_ATTACHMENT0; glDrawBuffers(1, &draw_buffer); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) Util_FatalError("Could not create a frame buffer object\n"); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, render.window->Width, render.window->Height); Util_CheckGLError(); } void Render_BeginFrame() { glClearColor(0.0f, 0.0f, 0.39f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, render.shadow_fbo); glViewport(0, 0, render.shadow_width, render.shadow_height); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void Render_LoadLights(Shader *s, const Light *lights, int n) { Vec3 light_positions[MAX_LIGHTS]; Vec4 light_colors[MAX_LIGHTS]; Vec3 attenuation[MAX_LIGHTS]; int i; /* Default light in case we are not given enough lights (n < 4) */ static const Light defaultLight = { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f } }; for(i = 0; i < MAX_LIGHTS; i++) { if(i < n) { light_positions[i] = lights[i].position; light_colors[i] = lights[i].color; attenuation[i] = lights[i].attenuation; } else { light_positions[i] = defaultLight.position; light_colors[i] = defaultLight.color; attenuation[i] = defaultLight.attenuation; } } glUniform3fv(s->lightPosition, MAX_LIGHTS, (float *)light_positions); glUniform4fv(s->lightColor, MAX_LIGHTS, (float *)light_colors); glUniform3fv(s->lightAttenuation, MAX_LIGHTS, (float *)attenuation); } /****************************************************************************** * * * Function Name: Render_DrawEntity * * * * Specific shader layout * * -> extra0 texture atlas number of rows * * -> extra1 texture atlas xy offset * * * *******************************************************************************/ void Render_DrawEntity(Shader *s, Mat4 *projectedViewMatrix, Entity *entity) { Mesh *mesh = entity->model->mesh; /*We need the model to world matrix in our shader in order to rotate the normals*/ Mat4 modelTransform = Entity_GetModelTransform(entity); Mat4 totalMatrix; /** TEMP **/ /** TEMP**/ glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data); totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data); glUniform1i(s->Texture, 0); texture_bind(entity->texture, 0); glUniform1f(s->extra0, entity->texture->number_of_rows); Vec2 tex_offset = Entity_GetTexOffset(entity); glUniform2fv(s->extra1, 1, (float *)&tex_offset); glBindVertexArray(mesh->vao); glDrawElements(GL_TRIANGLES, mesh->num_indices, GL_UNSIGNED_SHORT, NULL); glBindVertexArray(0); } /****************************************************************************** * * * Function Name: Render_DrawTerrain * * * * Specific shader layout * * -> extra0 Texture_Background * * -> extra1 Texture_R * * -> extra2 Texture_G * * -> extra3 Texture_B * * -> extra4 Texture_BlendMap * * * *******************************************************************************/ void Render_DrawTerrain(Shader *s, Mat4 *projectedViewMatrix, Terrain *terrain) { Mat4 totalMatrix; Mat4 modelTransform; /* We need the model to world matrix in our shader in order to rotate the normals */ modelTransform = mat4_translate(&terrain->position); glUniformMatrix4fv(s->modelToWorld, 1, GL_FALSE, modelTransform.data); totalMatrix = mat4_mul(projectedViewMatrix, &modelTransform); glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalMatrix.data); /** Set textures for the terrain **/ glUniform1i(s->extra0, 0); glUniform1i(s->extra1, 1); glUniform1i(s->extra2, 2); glUniform1i(s->extra3, 3); glUniform1i(s->extra4, 4); texture_bind(terrain->textures.texture[0], 0); texture_bind(terrain->textures.texture[1], 1); texture_bind(terrain->textures.texture[2], 2); texture_bind(terrain->textures.texture[3], 3); texture_bind(terrain->blendmap, 4); /**********************************/ glBindVertexArray(terrain->mesh->vao); glDrawElements(GL_TRIANGLES, terrain->mesh->num_indices, GL_UNSIGNED_SHORT, NULL); glBindVertexArray(0); } void Render_DrawSky(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix, Skybox *sky) { Mat4 myViewMatrix = *viewMatrix; Mat4 totalTransform; Mat4 rotateMatrix = mat4_rotate_y(sky->rotation); sky->rotation += SKYBOX_ROTATION_SPEED * Time_GetFrameTime(); /* We don't want to move the skybox around (We want it to stay with the camera in the midle), just rotate it with the camera so we remove the translations components of the matrix */ myViewMatrix.data[0 + 3 * 4] = 0.0f; myViewMatrix.data[1 + 3 * 4] = 0.0f; myViewMatrix.data[2 + 3 * 4] = 0.0f; myViewMatrix = mat4_mul(&myViewMatrix, &rotateMatrix); totalTransform = mat4_mul(projectionMatrix, &myViewMatrix); glUniformMatrix4fv(s->totalTransform, 1, GL_FALSE, totalTransform.data ); texture_bind(sky->texture, 0); glUniform1i(s->Texture, 0); glBindVertexArray(sky->cube->vao); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); } /****************************************************************************** * * * Function Name: Render_DrawParticles * * * * Specific shader layout * * -> extra0 texture atlas number of rows * * -> extra1 texture atlas xy offset * * * *******************************************************************************/ void Render_DrawParticles(Shader *s, Mat4 *viewMatrix, Mat4 *projectionMatrix) { Mat4 modelTransform, modelViewMatrix, totalTransform, scale; Particle *c = NULL; ParticleSystem *sys = NULL; int num_particles = 0; int i, j; glEnable(GL_BLEND); glDepthMask(GL_FALSE); glUniform1i(s->Texture, 0); for(i = 0; i < particles.num_systems; i++) { sys = particles.systems[i]; texture_bind(sys->texture, 0); glUniform1f(s->extra0, sys->texture->number_of_rows); /* Orphane the buffer */ glBindBuffer(GL_ARRAY_BUFFER, render.instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 18 * MAX_PARTICLES_PER_SYSTEM, NULL, GL_STREAM_DRAW); if(sys->additive) glBlendFunc(GL_SRC_ALPHA, GL_ONE); else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for(j = 0; j < sys->num_particles; j++) { c = &sys->particles[j]; modelTransform = mat4_translate(&c->position); scale = mat4_scale(c->scale, c->scale, c->scale); modelTransform = mat4_mul(&modelTransform, &scale); /* We eliminate the rotation from the view matrix so the particle is always facing the camera, for this we add the transposed matrix from the rotation part of the viewmatrx and put it on the model transform matrix */ modelTransform.data[0] = viewMatrix->data[0]; modelTransform.data[4] = viewMatrix->data[1]; modelTransform.data[8] = viewMatrix->data[2]; modelTransform.data[1] = viewMatrix->data[4]; modelTransform.data[5] = viewMatrix->data[5]; modelTransform.data[9] = viewMatrix->data[6]; modelTransform.data[2] = viewMatrix->data[8]; modelTransform.data[6] = viewMatrix->data[9]; modelTransform.data[10] = viewMatrix->data[10]; modelViewMatrix = mat4_mul(viewMatrix, &modelTransform); totalTransform = mat4_mul(projectionMatrix, &modelViewMatrix); /* Load the texture atlas coods and MVP matrix */ glBufferSubData(GL_ARRAY_BUFFER, num_particles * sizeof(GLfloat), sizeof(Vec2), &c->tex_offset); glBufferSubData(GL_ARRAY_BUFFER, (num_particles + 2) * sizeof(GLfloat), sizeof(Mat4), totalTransform.data); num_particles += 18; } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(render.default_quad->vao); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, num_particles / 18); } glBindVertexArray(0); glDepthMask(GL_TRUE); glDisable(GL_BLEND); } void Render_EndFrame() { glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, render.window->Width, render.window->Height); } void Render_Shutdown() { int i; glDeleteTextures(1, &render.shadow_map); glDeleteFramebuffers(1, &render.shadow_fbo); glDeleteBuffers(1, &render.instance_vbo); /* Destroy all created textures */ for(i = 0; i < render.num_textures; i++) { texture_purge( render.textures[i] ); free(render.textures[i]); } /* Destroy all created models */ for(i = 0; i < render.num_models; i++) { model_purge(render.models[i]); free(render.models[i]); } for(i = 0; i < render.num_meshes; i++) { mesh_purge(render.meshes[i]); free(render.meshes[i]); } /* Destroy all created shaders */ for(i = 0; i < render.num_shaders; i++) { shader_purge(render.shaders[i]); free(render.shaders[i]); } /* Just for checking */ printf("%d textures were deleted!\n", render.num_textures); printf("%d models were deleted!\n", render.num_models); printf("%d shaders were deleted!\n", render.num_shaders); printf("%d meshes were deleted!\n", render.num_meshes); /* Clear everything */ memset( &render, 0, sizeof(Renderer) ); }