polyadvent

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

update.c (15371B)


      1 
      2 #include "gl.h"
      3 #include "update.h"
      4 #include "terrain_collision.h"
      5 #include "util.h"
      6 #include "mat4.h"
      7 #include "vec3.h"
      8 #include "camera.h"
      9 #include "poisson.h"
     10 #include "uniform.h"
     11 #include "game.h"
     12 #include "mat_util.h"
     13 #include "resource.h"
     14 #include "shader.h"
     15 #include "file.h"
     16 #include "debug.h"
     17 #include <math.h>
     18 
     19 
     20 static void entity_movement(struct game *game, struct entity *ent)
     21 {
     22     static const float move_accel = 1.0f;
     23     static const float max_speed = 10.0f;
     24     struct node *node = get_node(&ent->node_id);
     25 
     26     float vel[3];
     27 
     28     float amt = 10.0 * game->dt;
     29 
     30     if (game->input.keystates[SDL_SCANCODE_W]) {
     31         vec3_forward(ent->velocity, node->orientation, V3(0,amt,0), vel);
     32         if (vec3_lengthsq(vel) <= max_speed*max_speed)
     33             vec3_copy(vel, ent->velocity);
     34     }
     35 }
     36 
     37 static void movement(struct game *game, struct node *node, float speed_mult)
     38 {
     39     float amt = 3.0 * game->dt;
     40     float turn = 1.0 * game->dt;
     41 
     42     float x_axis = (float)game->input.axis[0] / (float)MAX_AXIS_VALUE;
     43     float y_axis = (float)game->input.axis[1] / (float)MAX_AXIS_VALUE;
     44 
     45     amt *= speed_mult;
     46 
     47     if ((game->input.modifiers & KMOD_SHIFT) ||
     48         is_button_down(&game->input, SDL_CONTROLLER_BUTTON_LEFTSTICK))
     49     {
     50         amt *= 20;
     51     }
     52 
     53     // joystick movement
     54     node_forward(node, V3(0,amt*y_axis, 0));
     55     node_forward(node, V3(amt*x_axis, 0, 0));
     56 
     57 
     58     if (game->input.keystates[SDL_SCANCODE_A])
     59         node_forward(node, V3(-amt,0,0));
     60 
     61     if (game->input.keystates[SDL_SCANCODE_UP])
     62         node_forward(node, V3(0,0,amt));
     63 
     64     if (game->input.keystates[SDL_SCANCODE_DOWN])
     65         node_forward(node, V3(0,0,-amt));
     66 
     67     if (game->input.keystates[SDL_SCANCODE_D])
     68         node_forward(node, V3(amt,0,0));
     69 
     70     if (game->input.keystates[SDL_SCANCODE_W])
     71         node_forward(node, V3(0,amt,0));
     72 
     73     if (game->input.keystates[SDL_SCANCODE_S])
     74         node_forward(node, V3(0,-amt,0));
     75 
     76     if (game->input.keystates[SDL_SCANCODE_K])
     77         node_forward(node, V3(0, 0,amt));
     78 
     79     if (game->input.keystates[SDL_SCANCODE_J])
     80         node_forward(node, V3(0, 0,-amt));
     81 
     82     if (game->input.keystates[SDL_SCANCODE_E])
     83         node_rotate(node, V3(0, 0, turn));
     84 
     85     if (game->input.keystates[SDL_SCANCODE_Q])
     86         node_rotate(node, V3(0, 0, -turn));
     87 
     88     /* if (game->input.keystates[SDL_SCANCODE_DOWN]) */
     89     /*   node_translate(node, V3(0, 0, -amt)); */
     90 
     91     if (was_key_pressed_this_frame(game, SDL_SCANCODE_P)) {
     92         debug("%f %f %f ",
     93                 node->pos[0],
     94                 node->pos[1],
     95                 node->pos[2]);
     96         node_recalc(node);
     97         grid_pos_debug(node->label, &game->terrain, node_world(node));
     98         /* mat4_print(node->mat); */
     99     }
    100 }
    101 
    102 static void remap_samples(struct point *points, int n_samples,
    103                                     double size)
    104 {
    105     double middle = size / 2.0;
    106 
    107     for (int i = 0; i < n_samples; ++i) {
    108         struct point *point = &points[i];
    109 
    110         /* double x = point->x/size; */
    111         /* double y = point->y/size; */
    112         double dx = point->x - middle;
    113         double dy = point->y - middle;
    114         double dist = sqrt(dx*dx + dy*dy);
    115         double nx = dx / dist;
    116         double ny = dy / dist;
    117         double factor = -log(dist)*50.0;
    118         point->x += nx * factor;
    119         point->y += ny * factor;
    120     }
    121 }
    122 
    123 static void player_terrain_collision(struct terrain *terrain, struct node *node) {
    124     // player movement
    125     static vec3 last_pos[3] = {0};
    126 
    127     if (!vec3_approxeq(node->pos, last_pos)) {
    128         float player_z = node->pos[2];
    129 
    130         float terrain_z =
    131             terrain->fn(terrain, node->pos[0], node->pos[1]);
    132 
    133         float inset =
    134             min(0.0, player_z - terrain_z);
    135 
    136         if (inset <= 0)
    137             node_translate(node, V3(0.0, 0.0, -inset));
    138     }
    139 
    140 }
    141 
    142 static void player_movement(struct game *game, struct entity *player) {
    143     /* if (player->flags & ENT_ON_GROUND) */
    144     /*     entity_movement(game, player); */
    145     struct node *node = get_node(&player->node_id);
    146     movement(game, node, 2.0);
    147 }
    148 
    149 
    150 #ifdef DEBUG
    151 static int try_reload_shaders(struct resources *res) {
    152 	int ret;
    153     for (int i = 0; i < NUM_PROGRAMS; ++i) {
    154         struct gpu_program *program = &res->programs[i];
    155         ret = reload_program(program);
    156 
    157         if (ret == 2) {}
    158         else if (ret == 1)
    159             printf("reload %s success.\n", program->shaders[0].filename);
    160         else
    161             printf("reload %s failed.\n", program->shaders[0].filename);
    162 
    163         // failure ok, clear any errors
    164         glGetError();
    165     }
    166 
    167 
    168 
    169 
    170 	return ret;
    171 }
    172 #endif
    173 
    174 void resize_fbos(struct entity *player, struct fbo *shadow_buffer,
    175                  float *m4_ortho, int width, int height)
    176 {
    177     if (shadow_buffer->handle) {
    178         // TODO: remove once delete_fbo deletes attachments
    179         glDeleteTextures(1, &shadow_buffer->attachments[1]);
    180         glDeleteRenderbuffers(1, &shadow_buffer->attachments[0]);
    181         delete_fbo(shadow_buffer);
    182     }
    183 
    184     // TODO: compute better bounds based
    185     const float factor = 5.5;
    186 
    187     struct model *model   = get_model(&player->model_id); assert(model);
    188     struct geometry *geom = get_geometry(&model->geom_id); assert(geom);
    189 
    190     float left   = geom->min[0] - factor;
    191     float right  = geom->max[0] + factor;
    192     float bottom = geom->min[1] - factor;
    193     float top    = geom->max[1] + factor/2.0;
    194 
    195     /* float left   = -factor; */
    196     /* float right  = factor; */
    197     /* float bottom = factor; */
    198     /* float top    = -factor; */
    199 
    200     const float near = -5.0;
    201     const float far = 5.0;
    202 
    203     // default ortho screenspace projection
    204     mat4_ortho(left, right, bottom, top, near, far, m4_ortho);
    205 
    206     create_fbo(shadow_buffer, width, height );
    207     /* fbo_attach_renderbuffer(&res->shadow_buffer, GL_DEPTH24_STENCIL8, */
    208     /*                         GL_DEPTH_STENCIL_ATTACHMENT); */
    209 
    210     /* fbo_attach_color_texture(&res->shadow_buffer); */
    211     fbo_attach_depth_texture(shadow_buffer);
    212 
    213     check_fbo(shadow_buffer);
    214 
    215     /* fbo_attach_texture(&res->shadow_buffer, GL_DEPTH_COMPONENT16, */
    216     /*                    GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */
    217 
    218 }
    219 
    220 // TODO: match based on some real concept of time
    221 static void day_night_cycle(float time, struct resources *res) {
    222     float val = time * 0.0001;
    223     float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */
    224     struct entity *player = get_player(res);
    225     struct node *pnode = get_node(&player->node_id);
    226     assert(pnode);
    227     struct node *suncam = get_node(&res->sun_camera_id);
    228     assert(suncam);
    229 
    230     float light_pos[3];
    231 
    232     float g = 0.6;
    233     float b = 0.4;
    234     res->sun_color[0] = 1.0;
    235     res->sun_color[1] = g+intensity*(1.0-g);
    236     res->sun_color[2] = b+intensity*(1.0-b);
    237 
    238     /* res->sun_color[0] = 1.0; */
    239     /* res->sun_color[1] = 1.0; */
    240     /* res->sun_color[2] = 1.0; */
    241 
    242     /* vec3_scale(res->sun_color, res->light_intensity, gtmp); */
    243 
    244     /* float intensity = angle <= 0.5 */
    245     /*     ? clamp(roots, darkest, 1.0) */
    246     /*     : clamp(-roots * 0.4, darkest, 0.5); */
    247 
    248     res->light_intensity = intensity;
    249 
    250     /* vec3_normalize(res->light_intensity, res->light_intensity); */
    251 
    252     res->light_dir[0] = 0.0;
    253     /* res->light_dir[1] = sin(val); */
    254     /* res->light_dir[2] = cos(val) + 1.0; */
    255     res->light_dir[1] = 0.8;
    256     res->light_dir[2] = 0.8;
    257 
    258     vec3_normalize(res->light_dir, res->light_dir);
    259 
    260     /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */
    261     /*        n, res->light_dir[1], res->light_dir[2]); */
    262 
    263     vec3_add(pnode->pos, res->light_dir, light_pos);
    264 
    265     /* float target[3]; */
    266     /* float hh = player->model.geom.max[2] / 2.0; */
    267     /* vec3_copy(player->node.pos, target); */
    268     /* target[2] += 2.0; */
    269 
    270     look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat);
    271     /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */
    272 }
    273 
    274 static void gravity(struct game *game) {
    275     struct entity *player = get_player(&game->test_resources);
    276 
    277     if (player->flags & ENT_ON_GROUND)
    278         return;
    279 
    280     struct node   *pnode  = get_node(&player->node_id);
    281     assert(pnode);
    282 
    283     static const float g = -1.0;
    284     vec3_add(player->velocity, V3(0.0, 0.0, g * game->dt), player->velocity);
    285 }
    286 
    287 void orbit_update_from_mouse(struct orbit *camera, struct input *input,
    288                              float mouse_sens, struct entity *player,
    289                              float dt)
    290 {
    291     float target[3];
    292     struct node *target_node     = get_node(&player->node_id);
    293     struct node *cam_node        = get_node(&camera->node_id);
    294     struct model *pmodel         = get_model(&player->model_id); assert(pmodel);
    295     struct geometry *player_geom = get_geometry(&pmodel->geom_id); assert(player_geom);
    296 
    297     assert(target_node);
    298     assert(cam_node);
    299 
    300     node_recalc(target_node);
    301     vec3_copy(node_world(target_node), target);
    302     assert(player_geom->max[2] != 0);
    303     vec3_add(target, V3(0.0, 0.0, player_geom->max[2]), target);
    304     /* vec3_add(target, V3(0.0, 0.0, 10.0), target); */
    305 
    306     float mx = 0.0, my = 0.0;
    307     if (input_is_dragging(input, SDL_BUTTON_LEFT) ||
    308         input_is_dragging(input, SDL_BUTTON_RIGHT)) {
    309         mx = -input->mdx * mouse_sens * dt;
    310         my = -input->mdy * mouse_sens * dt;
    311     }
    312 
    313     // zoom
    314     if (input->keystates[SDL_SCANCODE_V]) {
    315         if (input->modifiers & KMOD_SHIFT)
    316             camera->coords.radius += dt * 100.0;
    317         else
    318             camera->coords.radius -= dt * 100.0;
    319 
    320     }
    321     else if (input->wheel_y) {
    322         camera->coords.radius += input->wheel_y * dt * 100.0;
    323     }
    324 
    325     camera->coords.radius = max(1.0, camera->coords.radius);
    326 
    327     camera->coords.azimuth     += mx;
    328     camera->coords.inclination += my;
    329     /* printf("coords azimuth %f inclination %f radius %f\n", */
    330     /*        camera->coords.azimuth, */
    331     /*        camera->coords.inclination, */
    332     /*        camera->coords.radius); */
    333 
    334     spherical_look_at(&camera->coords, target, cam_node->mat);
    335 
    336 }
    337 
    338 static void camera_keep_above_ground(struct terrain *terrain,
    339                                      struct node *camera) {
    340     if (static_entities()[entity_terrain].flags & ENT_INVISIBLE)
    341         return;
    342     float move[3];
    343     float *camworld = node_world(camera);
    344     float pen;
    345     static const float penlim = 1.0;
    346     struct tri *tri = collide_terrain(terrain, camworld, move, &pen);
    347 
    348     if (!tri)
    349         return;
    350 
    351     if (pen < penlim) {
    352         float dir[3], above[3];
    353         vec3_normalize(move, dir);
    354         vec3_scale(dir, pen < 0 ? penlim : -penlim, above);
    355         vec3_add(camworld, move, camworld);
    356         vec3_add(camworld, above, camworld);
    357         /* vec3_add(move, above, move); */
    358         /* vec3_add(camworld, move, camworld); */
    359     }
    360 }
    361 
    362 static void entity_jump(struct entity *ent, float amount)
    363 {
    364     float dir[3];
    365     debug("jumping\n");
    366     vec3_normalize(ent->velocity, dir);
    367     vec3_add(dir, V3(0, 0, amount), dir);
    368     vec3_add(ent->velocity, dir, ent->velocity);
    369 }
    370 
    371 static void player_update(struct game *game, struct entity *player)
    372 {
    373 
    374     struct resources *res = &game->test_resources;
    375     struct orbit *camera = &res->orbit_camera;
    376     struct node *node = get_node(&player->node_id);
    377     struct node *cam_node = get_node(&res->camera_node_id);
    378     assert(node);
    379     assert(cam_node);
    380 
    381     orbit_update_from_mouse(camera, &game->input, game->user_settings.mouse_sens,
    382                             player, game->dt);
    383 
    384     camera_keep_above_ground(&game->terrain, cam_node);
    385 
    386     // move player camera toward camera orientation
    387     if (input_is_dragging(&game->input, SDL_BUTTON_RIGHT)) {
    388         float yaw = game->test_resources.orbit_camera.coords.azimuth;
    389         quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation);
    390     }
    391 
    392     struct terrain *terrain = &game->terrain;
    393 
    394     /* player_terrain_collision(terrain, node); */
    395 
    396     float move[3];
    397     float pos[3];
    398     float pen;
    399     vec3_copy(node_world(node), pos);
    400     /* debug("node_world(player) %f %f %f\n", pos[0], pos[1], pos[2]); */
    401     struct tri *tri = collide_terrain(terrain, pos, move, &pen);
    402     /* node_translate(node, move); */
    403 
    404     if (tri) {
    405         if (vec3_eq(move, V3(0,0,0), 0.1)) {
    406             player->flags |= ENT_ON_GROUND;
    407         }
    408         else if (pen < 0) {
    409             node_translate(node, move);
    410             /* vec3_all(player->velocity, 0); */
    411             vec3_scale(player->velocity, 0.1, player->velocity);
    412         }
    413         else {
    414             player->flags &= ~ENT_ON_GROUND;
    415         }
    416     }
    417     else {
    418         static int tric = 0;
    419         debug("%d no tri\n", tric++);
    420     }
    421 
    422     if (player->flags & ENT_ON_GROUND &&
    423         (was_key_pressed_this_frame(game, SDL_SCANCODE_SPACE) ||
    424          was_button_pressed_this_frame(game, SDL_CONTROLLER_BUTTON_X))) {
    425         entity_jump(player, 2.0);
    426     }
    427 
    428     /* debug("player velocity %f %f %f\n", */
    429     /*       player->velocity[0], */
    430     /*       player->velocity[1], */
    431     /*       player->velocity[2]); */
    432 
    433     /* if (player->flags & ENT_AT_REST) */
    434     /*     vec3_scale(player->velocity, 0.00001, player->velocity); */
    435 
    436     node_translate(node, player->velocity);
    437     node_recalc(node);
    438 }
    439 
    440 
    441 
    442 void update (struct game *game) {
    443 	static int toggle_fog = 0;
    444 	static int needs_terrain_update = 0;
    445 	struct resources *res          = &game->test_resources;
    446     struct terrain   *terrain      = &game->terrain;
    447 	struct node      *root         = get_node(&game->test_resources.root_id);
    448     struct entity    *player       = get_player(res);
    449     struct node      *pnode        = get_node(&player->node_id);
    450     struct node      *cam_node     = get_node(&res->camera_node_id);
    451 
    452     assert(pnode);
    453     assert(cam_node);
    454 
    455     float *time = &res->time;
    456 	float *light = res->light_dir;
    457 
    458     gravity(game);
    459 
    460 	if (needs_terrain_update) {
    461 		/* update_terrain(terrain); */
    462 		needs_terrain_update = 0;
    463 	}
    464 
    465     /* spherical_dir(game->test_resources.camera.coords, camera_dir); */
    466     /* vec3_scale(camera_dir, -1, camera_dir); */
    467 
    468     if (game->input.modifiers & KMOD_ALT &&
    469         ideq(&res->camera_node_id, &res->free_camera_id))
    470     {
    471         struct node *freecam_node = get_node(&res->free_camera_id);
    472         assert(freecam_node);
    473         assert(streq(freecam_node->label, "freecam"));
    474         movement(game, freecam_node, 1.0);
    475     }
    476     else {
    477 		player_movement(game, player);
    478 	}
    479 
    480     assert(root->parent_id.generation == 0);
    481 
    482     player_update(game, player);
    483 
    484 #ifdef DEBUG
    485 	if (was_key_pressed_this_frame(game, SDL_SCANCODE_R))
    486 		try_reload_shaders(res);
    487 #endif
    488 
    489     if (was_key_pressed_this_frame(game, SDL_SCANCODE_F5)) {
    490         game->wireframe ^= 1;
    491     }
    492 
    493 	if (was_key_pressed_this_frame(game, SDL_SCANCODE_C)) {
    494 		printf("light_dir %f %f %f\n", light[0], light[1], light[2]);
    495     }
    496 
    497 	if (was_key_pressed_this_frame(game, SDL_SCANCODE_F))
    498 		toggle_fog = 1;
    499 
    500 	if (was_key_pressed_this_frame(game, SDL_SCANCODE_EQUALS)) {
    501         if (!ideq(&res->camera_node_id, &res->free_camera_id)) {
    502             debug("switching to freecam\n");
    503             res->camera_node_id = res->free_camera_id;
    504         }
    505         else {
    506             debug("switching to orbitcam\n");
    507             res->camera_node_id = res->orbit_camera.node_id;
    508         }
    509     }
    510 
    511 	if (toggle_fog) {
    512 		res->fog_on = !res->fog_on;
    513 		toggle_fog = 0;
    514 	}
    515 
    516     /* for (int i = 0; i < ) */
    517 
    518 	*time = SDL_GetTicks();
    519 
    520     day_night_cycle(*time, res);
    521 
    522 	node_recalc(root);
    523 }