polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

render.c (12179B)


      1 
      2 #include <assert.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 
      6 #include "gl.h"
      7 #include "game.h"
      8 #include "mat4.h"
      9 #include "vec3.h"
     10 #include "vbo.h"
     11 #include "shader.h"
     12 #include "geometry.h"
     13 #include "static_resources.h"
     14 #include "debug.h"
     15 #include "render.h"
     16 #include "skybox.h"
     17 #include "util.h"
     18 
     19 
     20 
     21 //    v6----- v5
     22 //   /|      /|
     23 //  v1------v0|
     24 //  | |     | |
     25 //  | |v7---|-|v4
     26 //  |/      |/
     27 //  v2------v3
     28 
     29 static const GLfloat cube_vertices[] = {
     30   0.5, 0.5, 0.5,  -0.5, 0.5, 0.5,  -0.5,-0.5, 0.5,   0.5,-0.5, 0.5,    // v0-v1-v2-v3 front
     31   0.5, 0.5,-0.5,   0.5, 0.5, 0.5,   0.5,-0.5, 0.5,   0.5,-0.5,-0.5,    // v5-v0-v3-v4 right
     32   -0.5, 0.5, 0.5,   0.5, 0.5, 0.5,   0.5, 0.5,-0.5,  -0.5, 0.5,-0.5,   // v1-v0-v5-v6 top
     33   -0.5, 0.5, 0.5,  -0.5, 0.5,-0.5,  -0.5,-0.5,-0.5,  -0.5,-0.5, 0.5,   // v1-v6-v7-v2 left
     34   0.5,-0.5, 0.5,  -0.5,-0.5, 0.5,  -0.5,-0.5,-0.5,   0.5,-0.5,-0.5,    // v3-v2-v7-v4 bottom
     35  -0.5, 0.5,-0.5,   0.5, 0.5,-0.5,   0.5,-0.5,-0.5,  -0.5,-0.5,-0.5     // v4-v7-v6-v5 back
     36 };
     37 
     38 
     39 static const GLfloat cube_normals[] = {
     40   0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1, // front
     41   1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0, // right
     42   0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0, // top
     43  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0, // left
     44   0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0, // bottom
     45   0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1  // back
     46 };
     47 
     48 
     49 static const GLushort cube_indices[] = {
     50    0, 1, 2,   0, 2, 3,    // front
     51    4, 5, 6,   4, 6, 7,    // right
     52    8, 9,10,   8,10,11,    // top
     53   12,13,14,  12,14,15,    // left
     54   16,17,18,  16,18,19,    // bottom
     55   20,21,22,  20,22,23
     56 };
     57 
     58 static const float bias_matrix[] = {
     59   0.5, 0.0, 0.0, 0.0,
     60   0.0, 0.5, 0.0, 0.0,
     61   0.0, 0.0, 0.5, 0.0,
     62   0.5, 0.5, 0.5, 1.0
     63 };
     64 
     65 void
     66 init_gl(struct resources *resources, int width, int height) {
     67     struct shader vertex, terrain_vertex, terrain_geom, fragment, fragment_smooth;
     68     struct shader terrain_teval, terrain_tc;
     69     float tmp_matrix[16];
     70     int ok = 0;
     71 
     72     glEnable(GL_DEPTH_TEST);
     73     glEnable(GL_CULL_FACE);
     74     glCullFace(GL_BACK);
     75 
     76     glEnable(GL_MULTISAMPLE);
     77     check_gl();
     78 
     79 	// Shaders
     80 	ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), &vertex);
     81 	rtassert(ok, "vertex-color shader");
     82 
     83     ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"),
     84                      &terrain_vertex);
     85 	rtassert(ok, "terrain vertex shader");
     86 	check_gl();
     87 
     88     /* ok = make_shader(GL_GEOMETRY_SHADER, SHADER("terrain.g.glsl"), */
     89     /*                  &terrain_geom); */
     90     /* 	assert(ok && "terrain geometry shader"); */
     91 
     92     /* ok = make_shader(GL_TESS_CONTROL_SHADER, SHADER("terrain.tc.glsl"), */
     93     /*                  &terrain_tc); */
     94     /* 	assert(ok && "terrain tessellation control shader"); */
     95     /* 	check_gl(); */
     96 
     97     /* ok = make_shader(GL_TESS_EVALUATION_SHADER, SHADER("terrain.te.glsl"), */
     98     /*                  &terrain_teval); */
     99     /* 	assert(ok && "terrain tessellation eval shader"); */
    100     /* 	check_gl(); */
    101 
    102 	ok = make_shader(GL_FRAGMENT_SHADER, SHADER("main.f.glsl"), &fragment);
    103 	rtassert(ok, "default fragment shader");
    104 	check_gl();
    105 
    106 	// camera
    107 	mat4_perspective(90 /* fov */,
    108 			 (float)width / height,
    109 			 1,
    110 			 5000,
    111 			 resources->proj_persp);
    112 
    113 	/* Shader program */
    114     /* struct shader *terrain_shaders[] = */
    115     /*     { &terrain_vertex, &fragment, &terrain_tc, &terrain_teval, */
    116     /*       &terrain_geom }; */
    117 
    118     /* struct shader *terrain_shaders[] = */
    119     /*     { &terrain_vertex, &fragment, &terrain_tc, &terrain_teval }; */
    120 
    121     /* struct shader *terrain_shaders[] = */
    122     /*     { &terrain_vertex, &fragment, &terrain_geom }; */
    123 
    124     struct shader *terrain_shaders[] =
    125         { &terrain_vertex, &fragment };
    126 
    127     ok = make_program_from_shaders(terrain_shaders, ARRAY_SIZE(terrain_shaders),
    128                                    &resources->programs[TERRAIN_PROGRAM]);
    129 
    130     // TODO: replace rtassert with error reporting/handling
    131 	rtassert(ok, "terrain program");
    132     check_gl();
    133 
    134 	ok = make_program(&vertex, &fragment, &resources->programs[DEFAULT_PROGRAM]);
    135 	rtassert(ok, "vertex-color program");
    136     check_gl();
    137 
    138     GLuint programs[] =
    139         { resources->programs[TERRAIN_PROGRAM].handle
    140         , resources->programs[DEFAULT_PROGRAM].handle
    141         };
    142 
    143     // uniforms shared between all shaders
    144     for (size_t i = 0; i < ARRAY_SIZE(programs); ++i) {
    145         GLuint handle = programs[i];
    146 
    147         // Program variables
    148         resources->uniforms.camera_position =
    149             glGetUniformLocation(handle, "camera_position");
    150         check_gl();
    151 
    152         /* resources->uniforms.depth_vp = */
    153         /*     glGetUniformLocation(handle, "depth_vp"); */
    154         /* check_gl(); */
    155 
    156         resources->uniforms.depth_mvp =
    157             glGetUniformLocation(handle, "depth_mvp");
    158         check_gl();
    159 
    160         resources->uniforms.light_intensity =
    161             glGetUniformLocation(handle, "light_intensity");
    162         check_gl();
    163 
    164         resources->uniforms.sky_intensity =
    165             glGetUniformLocation(handle, "sky_intensity");
    166         check_gl();
    167 
    168         resources->uniforms.time =
    169             glGetUniformLocation(handle, "time");
    170         check_gl();
    171 
    172         resources->uniforms.light_dir =
    173             glGetUniformLocation(handle, "light_dir");
    174         check_gl();
    175 
    176         resources->uniforms.sun_color =
    177             glGetUniformLocation(handle, "sun_color");
    178         check_gl();
    179 
    180         resources->uniforms.fog_on =
    181             glGetUniformLocation(handle, "fog_on");
    182         check_gl();
    183 
    184         /* resources->uniforms.diffuse_on = */
    185         /*     glGetUniformLocation(handle, "diffuse_on"); */
    186         /* check_gl(); */
    187 
    188         resources->uniforms.model =
    189             glGetUniformLocation(handle, "model");
    190         check_gl();
    191 
    192         resources->uniforms.mvp =
    193             glGetUniformLocation(handle, "mvp");
    194         check_gl();
    195 
    196         /* resources->uniforms.model_view = */
    197         /*     glGetUniformLocation(handle, "model_view"); */
    198 
    199         resources->uniforms.normal_matrix =
    200             glGetUniformLocation(handle, "normal_matrix");
    201         check_gl();
    202 
    203         resources->vertex_attrs[va_normal] =
    204             (gpu_addr)glGetAttribLocation(handle, "normal");
    205         check_gl();
    206 
    207         resources->vertex_attrs[va_position] =
    208             (gpu_addr)glGetAttribLocation(handle, "position");
    209         check_gl();
    210 
    211     }
    212 
    213     // TODO: auto-generate these somehow?
    214 	resources->vertex_attrs[va_color] =
    215         (gpu_addr)glGetAttribLocation(resources->programs[DEFAULT_PROGRAM]
    216                                         .handle, "color");
    217     /* assert(resources->attributes.color != 0xFFFFFFFF); */
    218     check_gl();
    219 }
    220 
    221 
    222 static void
    223 recalc_normals(GLint nm_uniform, mat4 *model_view, mat4 *normal) {
    224   mat4_inverse(model_view, normal);
    225   mat4_transpose(normal, normal);
    226   /* mat4_copy(model_view, normal); */
    227   glUniformMatrix4fv(nm_uniform, 1, 0, normal);
    228 }
    229 
    230 static void gamma_correct(float *c, float *d) {
    231     float gamma = 1.0/2.2;
    232     d[0] = powf(c[0], gamma);
    233     d[1] = powf(c[1], gamma);
    234     d[2] = powf(c[2], gamma);
    235 }
    236 
    237 void render (struct game *game, struct render_config *config) {
    238     float gtmp[3];
    239     struct resources *res = &game->test_resources;
    240 
    241 	glEnable(GL_DEPTH_TEST);
    242 
    243     float sky_intensity = clamp(res->light_intensity, 0.2, 1.0);
    244     vec3_scale(res->sun_color, sky_intensity, gtmp);
    245 
    246     glClearColor( gtmp[0], gtmp[1], gtmp[2], 1.0 ); //clear background screen to black
    247     /* glClearColor( 0.5294f * adjust, 0.8078f * adjust, 0.9216f * adjust, 1.0f ); //clear background screen to black */
    248     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    249 
    250     check_gl();
    251 
    252     static float id[MAT4_ELEMS] = { 0 };
    253     static float view[MAT4_ELEMS] = { 0 };
    254     static float view_proj[MAT4_ELEMS] = { 0 };
    255     static float normal_matrix[MAT4_ELEMS] = { 0 };
    256     static float model_view[MAT4_ELEMS] = { 0 };
    257     static float depth_mvp[MAT4_ELEMS] = { 0 };
    258     mat4_id(id);
    259     mat4_id(model_view);
    260 
    261     mat4 *mvp = res->test_mvp;
    262     mat4 *projection = config->projection;
    263     mat4 *light = res->light_dir;
    264 
    265     struct node *camera_node = get_node(&config->camera);
    266     assert(camera_node);
    267 
    268     const mat4 *camera = camera_node->mat;
    269     u32 num_entities;
    270 
    271     struct entity *entities =
    272         get_all_entities(&num_entities, NULL);
    273 
    274     struct gpu_program *current_program = NULL;
    275 
    276     struct gpu_program *terrain_program =
    277         &game->test_resources.programs[TERRAIN_PROGRAM];
    278 
    279     struct gpu_program *default_program =
    280         &game->test_resources.programs[DEFAULT_PROGRAM];
    281 
    282     /* mat4_multiply(view_proj, res->skybox.node.mat, mvp); */
    283 
    284     mat4_inverse((float*)camera, view);
    285     mat4_multiply(projection, view, view_proj);
    286 
    287     if (config->is_depth_pass) {
    288         glDisable(GL_CULL_FACE);
    289         mat4_multiply(bias_matrix, view_proj, config->depth_vp);
    290     }
    291     else {
    292         glCullFace(GL_BACK);
    293     }
    294 
    295     mat4_inverse((float *)camera, view);
    296     mat4_multiply(projection, view, view_proj);
    297 
    298     struct model *skybox_model = get_model(&res->skybox.model_id);
    299     assert(skybox_model);
    300 
    301     glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_model->texture);
    302     check_gl();
    303 
    304     for (u32 i = 0; i < num_entities; ++i) {
    305         struct entity *entity = &entities[i];
    306 
    307         if (entity->flags & ENT_INVISIBLE)
    308             continue;
    309 
    310         if (config->is_depth_pass && !(entity->flags & ENT_CASTS_SHADOWS))
    311             continue;
    312 
    313         // TODO this is a bit wonky, refactor this
    314         current_program = i == 0 ? terrain_program : default_program;
    315         glUseProgram(current_program->handle);
    316         check_gl();
    317 
    318 
    319         glUniform3f(res->uniforms.camera_position,
    320                     camera[M_X],
    321                     camera[M_Y],
    322                     camera[M_Z]);
    323 
    324         glUniform1i(res->uniforms.fog_on, res->fog_on);
    325         check_gl();
    326 
    327         glUniform3f(res->uniforms.light_dir, light[0], light[1], light[2]);
    328         check_gl();
    329 
    330         glUniform1f(res->uniforms.light_intensity, res->light_intensity);
    331         check_gl();
    332 
    333         glUniform1f(res->uniforms.sky_intensity, sky_intensity);
    334         check_gl();
    335 
    336         glUniform3f(res->uniforms.sun_color,
    337                     res->sun_color[0],
    338                     res->sun_color[1],
    339                     res->sun_color[2]);
    340         check_gl();
    341 
    342         struct node *node = get_node(&entity->node_id);
    343         assert(node);
    344         if (node == NULL)
    345             return;
    346 
    347         mat4_multiply(view_proj, node->mat, mvp);
    348         mat4_copy(node->mat, model_view);
    349         mat4_multiply(config->depth_vp, model_view, depth_mvp);
    350         glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, depth_mvp);
    351         check_gl();
    352 
    353         glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp);
    354         check_gl();
    355 
    356         glUniformMatrix4fv(res->uniforms.model, 1, 0, node->mat);
    357         check_gl();
    358 
    359         recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix);
    360         check_gl();
    361 
    362         struct model *model = get_model(&entity->model_id);
    363         assert(model);
    364         struct geometry *geo = get_geometry(&model->geom_id);
    365         /* debug("geo node %s\n", node->label); */
    366         assert(geo);
    367         render_geometry(geo, res->vertex_attrs, current_program);
    368         check_gl();
    369     }
    370 
    371     if (game->wireframe) {
    372         glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    373     }
    374     else {
    375         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    376     }
    377 
    378     if (!config->is_depth_pass) {
    379         mat4_inverse((float*)camera, view);
    380         mat4_remove_translations(view);
    381         mat4_multiply(projection, view, view_proj);
    382 
    383         render_skybox(&res->skybox, view_proj);
    384     }
    385 
    386     if (config->draw_ui)
    387         render_ui(&game->ui, view);
    388 
    389     //player
    390     // y tho
    391 
    392     // terrain
    393 
    394     /* glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); */
    395     /* glUniformMatrix4fv(res->uniforms.model_view, 1, 0, id); */
    396     /* glUniformMatrix4fv(res->uniforms.world, 1, 0, id); */
    397     /* glUniformMatrix4fv(res->uniforms.normal_matrix, 1, 0, id); */
    398     /* recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); */
    399     /* render_geom(res, geom, GL_TRIANGLES); */
    400     /* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); */
    401     /* render_geom(res, geom, GL_TRIANGLES); */
    402 }