polyadvent

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

commit 1a35612b18f3291266b0c4e84095c7e98d503cc9
parent 240e9581a202f39037bc124f0bf4457ee110974c
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 23 Sep 2021 20:14:24 -0700

split test game out of game engine

Diffstat:
M.gitignore | 2++
Mmain.c | 82++++++++++++++++++++++++++-----------------------------------------------------
Msrc/camera.c | 1+
Msrc/camera.h | 7+++----
Msrc/chess.c | 9++++-----
Msrc/chess.h | 4++--
Msrc/game.c | 148++++++-------------------------------------------------------------------------
Msrc/game.h | 36+++---------------------------------
Asrc/gpu.c | 23+++++++++++++++++++++++
Asrc/gpu.h | 12++++++++++++
Asrc/movement.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/movement.h | 7+++++++
Asrc/orbit_util.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/orbit_util.h | 5+++++
Msrc/quat.c | 4----
Msrc/quat.h | 7++++++-
Msrc/render.c | 239+++----------------------------------------------------------------------------
Msrc/render.h | 36++++++++++++++++++++++++++++++++----
Msrc/scene.c | 90-------------------------------------------------------------------------------
Msrc/scene.h | 6------
Msrc/shader.c | 3+--
Asrc/test_game.c | 779+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_game.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/update.c | 492-------------------------------------------------------------------------------
Msrc/update.h | 3+++
Msrc/util.h | 1+
Msrc/window.c | 12+++---------
Mtest/test_scene.c | 3++-
28 files changed, 1132 insertions(+), 1077 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -13,3 +13,5 @@ polyadvent /test/test_dae /data/models/*.mdl data/models/third-party-src/ +/.build-result +/.buildcmd diff --git a/main.c b/main.c @@ -20,6 +20,8 @@ #include "util.h" #include "window.h" +#include "test_game.h" + #include <stdio.h> @@ -37,77 +39,47 @@ int main(void) printf("seed %d\n", seed); srand(seed); - struct game game; - game.seed = seed; + struct game engine; + struct test_game test_game; + + engine.seed = seed; /* SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); */ int width = 640; int hello; int height = 480; - game_init(&game, width, height); - default_scene(&game); + game_init(&engine, width, height); + + init_test_game(&test_game, &engine.gpu, width, height); + + //reset_scene(&engine); + default_scene(&test_game); + //pbr_scene(&test_game); //chess_scene(&game); check_gl(); double last = hires_time_in_seconds(); - static float depth_vp[MAT4_ELEMS]; - mat4_id(depth_vp); - - struct render_config fbo_render_config = { - .draw_ui = 1, - .is_depth_pass = 1, - .camera = game.test_resources.sun_camera_id, - .projection = game.test_resources.proj_ortho, - .depth_vp = depth_vp - }; - - struct render_config default_config = { - .draw_ui = 1, - .is_depth_pass = 0, - .camera = game.test_resources.camera_node_id, - .projection = game.test_resources.proj_persp, - .depth_vp = depth_vp - }; - - - while (!game.quit) { - game.input.keystates = SDL_GetKeyboardState(NULL); - game.frame++; - process_events(&game.input, game.frame); - if (game.input.resized_height) { - /* printf("handling resize %d %d\n", game.input.resized_width, */ - /* game.input.resized_height); */ - handle_resize(&game, game.input.resized_width, game.input.resized_height); + + while (!engine.quit) { + engine.input.keystates = SDL_GetKeyboardState(NULL); + engine.frame++; + process_events(&engine.input, engine.frame); + if (engine.input.resized_height) { + printf("handling resize %d %d\n", engine.input.resized_width, + engine.input.resized_height); + handle_resize(&engine, engine.input.resized_width, engine.input.resized_height); } - //default_config.camera = game.test_resources.camera_node->mat; + //default_config.camera = engine.test_resources.camera_node->mat; double new_time = hires_time_in_seconds(); double frame_time = new_time - last; - game.dt = frame_time; - if (game.frame % 60 == 0) - printf("%f fps\n", 1000.0 / (frame_time*1000) ); - - update(&game); - - /* while (accumulator >= dt) { */ - /* t += dt; */ - /* accumulator -= dt; */ - /* } */ - - default_config.camera = game.test_resources.camera_node_id; - + engine.dt = frame_time; last = new_time; - struct fbo *fbo = &game.test_resources.shadow_buffer; - check_fbo(fbo); - bind_fbo(fbo); - /* glDrawBuffer(GL_NONE); */ - - render(&game, &fbo_render_config); - unbind_fbo(&game.test_resources.shadow_buffer); - render(&game, &default_config); + // render our game frame here + test_game_frame(&engine, &test_game); /* Swap front and back buffers */ - SDL_GL_SwapWindow(game.window); + SDL_GL_SwapWindow(engine.window); } /* free(slab_buffer); */ diff --git a/src/camera.c b/src/camera.c @@ -1,5 +1,6 @@ #include "camera.h" +#include "input.h" #include "mat_util.h" // should probably be a scene node diff --git a/src/camera.h b/src/camera.h @@ -7,11 +7,10 @@ #include "node.h" struct camera { - float frustum[16]; - node_id node_id; + float frustum[16]; + node_id node_id; }; -void -camera_follow(vec3 *cam_pos, vec3 *target, mat4 *cam); +void camera_follow(vec3 *cam_pos, vec3 *target, mat4 *cam); #endif /* POLYADVENT_CAMERA_H */ diff --git a/src/chess.c b/src/chess.c @@ -1,6 +1,5 @@ #include "chess.h" - #include "node.h" // v1------v0 @@ -179,11 +178,11 @@ static void setup_pieces(node_id *chessboard) { } -void chess_scene(struct game *game) +void chess_scene(struct test_game *game) { struct entity *ent = new_entity(NULL); struct node *node = get_node(&ent->node_id); assert(node); - struct entity *player = get_player(&game->test_resources); + struct entity *player = get_entity(&game->player_id); ent->model_id = get_model_by_name("icosphere", NULL); node_set_label(node, "sphere"); @@ -207,7 +206,7 @@ void chess_scene(struct game *game) // // setup camera // - struct spherical *coords = &game->test_resources.orbit_camera.coords; + struct spherical *coords = &game->orbit_camera.coords; coords->radius = 72.0; coords->inclination = 0.5; coords->azimuth = -7.86; @@ -217,7 +216,7 @@ void chess_scene(struct game *game) pnode->orientation[2] = -0.005; pnode->orientation[3] = -1.0; - node_id *cam_id = &game->test_resources.orbit_camera.node_id; + node_id *cam_id = &game->orbit_camera.node_id; struct node *cam_node = get_node(cam_id); assert(cam_node); setup_pieces(&player->node_id); diff --git a/src/chess.h b/src/chess.h @@ -2,8 +2,8 @@ #ifndef POLYADVENT_CHESS_H #define POLYADVENT_CHESS_H -#include "game.h" +#include "test_game.h" -void chess_scene(struct game *game); +void chess_scene(struct test_game *game); #endif /* POLYADVENT_CHESS_H */ diff --git a/src/game.c b/src/game.c @@ -35,19 +35,6 @@ bool was_button_pressed_this_frame(struct game *game, int button) return is_button_down_on_frame(&game->input, button, game->frame); } -struct entity *get_player(struct resources *res) { - struct entity *player = get_entity(&res->player_id); - assert(player); - return player; -} - -struct entity *get_terrain_entity(struct terrain *t) { - struct entity *ent = get_entity(&t->entity_id); - assert(ent); - return ent; -} - - static void init_user_settings(struct user_settings *settings) { SDL_SetRelativeMouseMode(SDL_TRUE); settings->mouse_sens = 0.1; @@ -72,127 +59,14 @@ void quit_game(struct game *game) } // TODO: cleanup -void init_misc(struct game *game, int width, int height) { - struct resources *res = &game->test_resources; - mat4 *mvp = res->test_mvp; - - init_id(&res->root_id); - init_id(&res->sun_camera_id); - init_id(&res->free_camera_id); - - struct node *root = new_node(&res->root_id); - struct node *sun_camera = new_node(&res->sun_camera_id); - - struct terrain *terrain = &game->terrain; - struct entity *player; - - assert(root->parent_id.generation == 0); - assert(root); - assert(sun_camera); - - mat4 *light_dir = res->light_dir; - +void init_misc(struct game *game) { game->quit = 0; game->frame = 0; + game->gpu.num_programs = 0; - const double size = 4000.0; - //double scale = 0.03; - double scale = 0.03; - - terrain->settings = (struct perlin_settings){ - .depth = 1, - .freq = scale * 0.08, - .o1 = 2.0, .o1s = 0.5, - .o2 = 4.0, .o2s = 0.25, - .amplitude = 70.0, - .ox = 0, - .oy = 0, - .exp = 5.3, - .scale = scale - }; - - debug("creating ui...\n"); - create_ui(&game->ui, width, height, &res->programs[UI_PROGRAM]); - check_gl(); - - init_terrain(terrain, size); - /* terrain->samples = load_samples(&seed, &terrain->n_samples); */ - terrain->n_samples = 0; - //create_terrain(terrain, size, game->seed); - load_terrain(terrain); - /* update_terrain(terrain, terrain->cell_size); */ - /* get_entity(&terrain->entity_id)->flags |= ENT_INVISIBLE; */ - - debug("creating skybox...\n"); - create_skybox(&res->skybox, &res->programs[SKYBOX_PROGRAM]); /* node_translate(&res->skybox.node, V3(-100.0, -100.0, 0.0)); */ - /* node_scale(&res->skybox.node, size/4.0); */ - - mat4_id(mvp); - - res->time = 0; - res->light_intensity = 0.8; - - light_dir[0] = 0.8; - light_dir[1] = 0.8; - light_dir[2] = 0.8; - - res->piece_color[0] = 1.0; - res->piece_color[1] = 1.0; - res->piece_color[2] = 1.0; - - res->sun_color[0] = 0.5; - res->sun_color[1] = 0.6; - res->sun_color[2] = 0.7; - - game->test_resources.fog_on = 0; - game->test_resources.diffuse_on = 0; - - node_init(root); - node_init(sun_camera); - new_orbit(&res->orbit_camera); - - node_set_label(root, "root"); - - // ENTITIES - - // player entity - init_id(&res->player_id); - player = new_entity(&res->player_id); - player->flags |= ENT_CASTS_SHADOWS; - struct node *pnode = get_node(&player->node_id); - assert(pnode); - - player->model_id = get_model_by_name("pirate_officer", NULL); - assert(!is_null_id(&player->model_id.id)); - - node_set_label(pnode, "player"); - /* node_rotate(pnode, V3(-5.0,0,0)); */ - node_attach(&player->node_id, &res->root_id); - assert(ideq(&pnode->parent_id, &res->root_id)); - - node_translate(pnode, V3(terrain->size/2.,terrain->size/2.,0.0)); - - // orbit camera - res->orbit_camera.coords.azimuth = -quat_yaw(pnode->orientation) - RAD(90.0); - res->orbit_camera.coords.inclination = RAD(60); - res->orbit_camera.coords.radius = 5.0; - res->camera_node_id = res->orbit_camera.node_id; - - // free camera - struct node *freecam = new_node(&res->free_camera_id); - node_set_label(freecam, "freecam"); - node_attach(&res->free_camera_id, &player->node_id); - quat_axis_angle(V3(1,0,0), -45, freecam->orientation); - node_rotate(freecam, V3(100, 0, 0)); - node_translate(freecam, V3(0,-40,20)); - - // FBO STUFF - init_fbo(&res->shadow_buffer); - resize_fbos(player, &res->shadow_buffer, res->proj_ortho, width, height); - // FBO STUFF END - - // TEXTURES - // END TEXTURES +//debug("creating ui...\n"); + //create_ui(&game->ui, width, height, &res->programs[UI_PROGRAM]); + //check_gl(); } /* @@ -219,17 +93,14 @@ void init_controller(struct input *input) { } */ -void init_resources(struct resources *res) -{ - memset(res, 0, sizeof(*res)); -} void game_init(struct game *game, int width, int height) { - init_resources(&game->test_resources); + game->width = width; + game->height = height; debug("init sdl...\n"); init_sdl(&game->window, width, height); debug("init gl...\n"); - init_gl(&game->test_resources, width, height); + init_gl(); debug("init entities...\n"); init_entity_system(); debug("init geom...\n"); @@ -249,5 +120,6 @@ void game_init(struct game *game, int width, int height) { init_input(&game->input); //init_controller(&game->input); debug("init misc...\n"); - init_misc(game, width, height); + init_misc(game); + } diff --git a/src/game.h b/src/game.h @@ -14,44 +14,16 @@ #include "terrain.h" #include "texture.h" #include "ui.h" +#include "gpu.h" #include <stdio.h> #define PLAYER_HEIGHT 1.73 -#define MAX_PROGRAMS 12 - /* * Global data used by our render callback: * NOTE: just for testing right now */ -struct resources { - struct vbo vertex_buffer, element_buffer, normal_buffer; - struct fbo shadow_buffer; - - struct gpu_program programs[MAX_PROGRAMS]; - - node_id root_id; - entity_id player_id; - struct geometry qh_test; - struct orbit orbit_camera; - node_id free_camera_id; - node_id camera_node_id; - node_id sun_camera_id; - - u32 test_cubemap; - float time; - bool fog_on, diffuse_on; - - struct skybox skybox; - float sun_color[3]; - float piece_color[3]; - float test_mvp[MAT4_ELEMS]; - float light_dir[3]; - float light_intensity; - float proj_persp[MAT4_ELEMS]; - float proj_ortho[MAT4_ELEMS]; -}; struct user_settings { float mouse_sens; @@ -63,17 +35,15 @@ struct game { int seed; int quit; int wireframe; + int width, height; float dt; u64 frame; struct user_settings user_settings; struct ui ui; - struct resources test_resources; struct input input; - struct terrain terrain; + struct gpu gpu; }; -struct entity *get_player(struct resources *); -struct entity *get_terrain_entity(struct terrain *); void game_init(struct game *game, int width, int height); void quit_game(struct game *game); void should_update(struct game *game); diff --git a/src/gpu.c b/src/gpu.c @@ -0,0 +1,23 @@ + +#include "gpu.h" +#include <stdio.h> + +int try_reload_shaders(struct gpu *gpu) { + int ret = 0; + for (int i = 0; i < gpu->num_programs; ++i) { + struct gpu_program *program = &gpu->programs[i]; + ret = reload_program(program, gpu->programs); + + if (ret == 2) {} + else if (ret == 1) + printf("reload %s success.\n", program->shaders[0].filename); + else + printf("reload %s failed.\n", program->shaders[0].filename); + + // failure ok, clear any errors + glGetError(); + } + + return ret; +} + diff --git a/src/gpu.h b/src/gpu.h @@ -0,0 +1,12 @@ +#pragma once + +#include "shader.h" + +#define MAX_GPU_PROGRAMS 12 + +struct gpu { + struct gpu_program programs[MAX_GPU_PROGRAMS]; + int num_programs; +}; + +int try_reload_shaders(struct gpu *gpu); diff --git a/src/movement.c b/src/movement.c @@ -0,0 +1,89 @@ + +#include "game.h" + +void movement(struct game *engine, struct node *node, float speed_mult) +{ + float amt = 3.0 * engine->dt; + float turn = 1.0 * engine->dt; + + float x_axis = (float)engine->input.axis[0] / (float)MAX_AXIS_VALUE; + float y_axis = (float)engine->input.axis[1] / (float)MAX_AXIS_VALUE; + + amt *= speed_mult; + + if ((engine->input.modifiers & KMOD_SHIFT) /*|| + is_button_down(&engine->input, SDL_CONTROLLER_BUTTON_LEFTSTICK)*/) { + amt *= 20; + } + + // joystick movement + node_forward(node, V3(0,amt*y_axis, 0)); + node_forward(node, V3(amt*x_axis, 0, 0)); + + if (engine->input.keystates[SDL_SCANCODE_A]) + node_forward(node, V3(-amt,0,0)); + + if (engine->input.keystates[SDL_SCANCODE_UP]) + node_forward(node, V3(0,0,amt)); + + if (engine->input.keystates[SDL_SCANCODE_DOWN]) + node_forward(node, V3(0,0,-amt)); + + if (engine->input.keystates[SDL_SCANCODE_D]) + node_forward(node, V3(amt,0,0)); + + if (engine->input.keystates[SDL_SCANCODE_W]) + node_forward(node, V3(0,amt,0)); + + if (engine->input.keystates[SDL_SCANCODE_S]) + node_forward(node, V3(0,-amt,0)); + + if (engine->input.keystates[SDL_SCANCODE_K]) + node_forward(node, V3(0, 0,amt)); + + if (engine->input.keystates[SDL_SCANCODE_J]) + node_forward(node, V3(0, 0,-amt)); + + if (engine->input.keystates[SDL_SCANCODE_E]) + node_rotate(node, V3(0, 0, turn)); + + if (engine->input.keystates[SDL_SCANCODE_Q]) + node_rotate(node, V3(0, 0, -turn)); + + /* if (engine->input.keystates[SDL_SCANCODE_DOWN]) */ + /* node_translate(node, V3(0, 0, -amt)); */ + + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_P)) { + debug("player %f %f %f quat %f %f %f %f\n", + node->pos[0], + node->pos[1], + node->pos[2], + node->orientation[0], + node->orientation[1], + node->orientation[2], + node->orientation[3] + ); + } +} + + +void entity_jump(struct entity *ent, float amount) +{ + float dir[3]; + vec3_normalize(ent->velocity, dir); + vec3_add(dir, V3(0, 0, amount), dir); + vec3_add(ent->velocity, dir, ent->velocity); +} + + +void gravity(struct entity *ent, float dt) { + if (ent->flags & ENT_ON_GROUND) + return; + + struct node *pnode = get_node(&ent->node_id); + assert(pnode); + + static const float g = -1.0; + vec3_add(ent->velocity, V3(0.0, 0.0, g * dt), ent->velocity); +} + diff --git a/src/movement.h b/src/movement.h @@ -0,0 +1,7 @@ +#pragma once + +#include "game.h" + +void movement(struct game *game, struct node *node, float speed_mult); +void entity_jump(struct entity *ent, float amount); +void gravity(struct entity *ent, float dt); diff --git a/src/orbit_util.c b/src/orbit_util.c @@ -0,0 +1,59 @@ + +#include "orbit.h" +#include "input.h" +#include "entity.h" + +void orbit_update_from_mouse(struct orbit *camera, struct input *input, + float mouse_sens, struct entity *player, + float dt) +{ + float target[3]; + struct node *target_node = get_node(&player->node_id); + struct node *cam_node = get_node(&camera->node_id); + struct model *pmodel = get_model(&player->model_id); assert(pmodel); + struct geometry *player_geom = get_geometry(&pmodel->geom_id); assert(player_geom); + + assert(target_node); + assert(cam_node); + + node_recalc(target_node); + vec3_copy(node_world(target_node), target); + assert(player_geom->max[2] != 0); + vec3_add(target, V3(0.0, 0.0, player_geom->max[2]), target); + /* vec3_add(target, V3(0.0, 0.0, 10.0), target); */ + + float mx = 0.0, my = 0.0; + if (input_is_dragging(input, SDL_BUTTON_LEFT) || + input_is_dragging(input, SDL_BUTTON_RIGHT)) { + mx = -input->mdx * mouse_sens * dt; + my = -input->mdy * mouse_sens * dt; + } + + // zoom + if (input->keystates[SDL_SCANCODE_V]) { + if (input->modifiers & KMOD_SHIFT) + camera->coords.radius += dt * 100.0; + else + camera->coords.radius -= dt * 100.0; + + } + else if (input->wheel_y) { + camera->coords.radius += input->wheel_y * dt * 100.0; + } + + camera->coords.radius = max(1.0, camera->coords.radius); + + camera->coords.azimuth += mx; + camera->coords.inclination += my; + + /* + printf("coords azimuth %f inclination %f radius %f\n", + camera->coords.azimuth, + camera->coords.inclination, + camera->coords.radius); + */ + + spherical_look_at(&camera->coords, target, cam_node->mat); + +} + diff --git a/src/orbit_util.h b/src/orbit_util.h @@ -0,0 +1,5 @@ +#pragma once + +void orbit_update_from_mouse(struct orbit *camera, struct input *input, + float mouse_sens, struct entity *player, + float dt); diff --git a/src/quat.c b/src/quat.c @@ -75,10 +75,6 @@ void quat_to_mat3(quat *quat, float *dest) { } -float quat_yaw(quat *q) { - return atan2(q[2],q[3])*2.0; -} - void quat_multiply_vec3(quat *quat, float *vec, float *dest) { float x = vec[0], y = vec[1], z = vec[2]; float qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3]; diff --git a/src/quat.h b/src/quat.h @@ -3,6 +3,8 @@ #ifndef POLYADVENT_QUAT4_ #define POLYADVENT_QUAT4_ +#include <math.h> + typedef float quat; #define QUAT(x,y,z,w) ((quat[4]){x,y,z,w}) @@ -11,8 +13,11 @@ void quat_multiply(quat *a, quat *b, quat *dest); void quat_axis_angle(float *axis, float angle, quat *dest); void quat_from_axes(float yaw, float pitch, float roll); void quat_to_mat3(quat *quat, float *dest); -float quat_yaw(quat *quat); void quat_multiply_vec3(quat *quat, float *vec, float *dest); quat *quat_inverse(quat *q, quat *dest); +static inline float quat_yaw(quat *q) { + return atan2(q[2],q[3])*2.0; +} + #endif /* POLYADVENT_QUAT4_ */ diff --git a/src/render.c b/src/render.c @@ -54,78 +54,23 @@ static const GLushort cube_indices[] = { 20,21,22, 20,22,23 }; -static const float bias_matrix[] = { - 0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0 -}; - -void init_gl(struct resources *resources, int width, int height) { - struct shader vertex, terrain_vertex, chess_piece_vertex, terrain_geom, fragment, fragment_smooth; - struct shader terrain_teval, terrain_tc; - float tmp_matrix[16]; - int ok = 0; - +void init_gl() +{ glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glEnable(GL_MULTISAMPLE); check_gl(); - - // Shaders - ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), - &vertex); - rtassert(ok, "vertex-color shader"); - - ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"), &terrain_vertex); - rtassert(ok, "terrain vertex shader"); - check_gl(); - - ok = make_shader(GL_VERTEX_SHADER, SHADER("chess-piece.v.glsl"), &chess_piece_vertex); - rtassert(ok, "chess-piece vertex shader"); - check_gl(); - - ok = make_shader(GL_FRAGMENT_SHADER, SHADER("main.f.glsl"), &fragment); - rtassert(ok, "default fragment shader"); - check_gl(); - - // camera - mat4_perspective(90 /* fov */, - (float)width / height, - 1, - 5000, - resources->proj_persp); - - struct gpu_program *programs = resources->programs; - struct gpu_program *program; - - ok = make_program("terrain", &terrain_vertex, &fragment, - &programs[TERRAIN_PROGRAM]); - // TODO: replace rtassert with error reporting/handling - rtassert(ok, "terrain program"); - check_gl(); - - ok = make_program("vertex-color", &vertex, &fragment, &programs[DEFAULT_PROGRAM]); - rtassert(ok, "vertex-color program"); - check_gl(); - - - program = &programs[CHESS_PIECE_PROGRAM]; - ok = make_program("chess-piece", &chess_piece_vertex, &fragment, program); - rtassert(ok, "chess-piece program"); - - find_uniforms(programs); } -static void -recalc_normals(GLint nm_uniform, mat4 *model_view, mat4 *normal) { - mat4_inverse(model_view, normal); - mat4_transpose(normal, normal); - /* mat4_copy(model_view, normal); */ - glUniformMatrix4fv(nm_uniform, 1, 0, normal); +void recalc_normals(GLint nm_uniform, mat4 *model_view, mat4 *normal) +{ + mat4_inverse(model_view, normal); + mat4_transpose(normal, normal); + /* mat4_copy(model_view, normal); */ + glUniformMatrix4fv(nm_uniform, 1, 0, normal); } static void gamma_correct(float *c, float *d) { @@ -135,171 +80,3 @@ static void gamma_correct(float *c, float *d) { d[2] = powf(c[2], gamma); } -static inline void uniform_3f(struct gpu_program *program, - enum uniform_id id, const float *v3) -{ - glUniform3f(program->uniforms[id].location, v3[0], v3[1], v3[2]); - check_gl(); -} - -static inline void uniform_1i(struct gpu_program *program, - enum uniform_id id, int i) -{ - glUniform1i(program->uniforms[id].location, i); - check_gl(); -} - -static inline void uniform_m4f(struct gpu_program *program, - enum uniform_id id, float *m) -{ - glUniformMatrix4fv(program->uniforms[id].location, 1, 0, m); - check_gl(); -} - -static inline void uniform_1f(struct gpu_program *program, - enum uniform_id id, float f) -{ - glUniform1f(program->uniforms[id].location, f); - check_gl(); -} - -void render (struct game *game, struct render_config *config) { - float gtmp[3]; - struct resources *res = &game->test_resources; - - glEnable(GL_DEPTH_TEST); - - float sky_intensity = clamp(res->light_intensity, 0.2, 1.0); - vec3_scale(res->sun_color, sky_intensity, gtmp); - - glClearColor( gtmp[0], gtmp[1], gtmp[2], 1.0 ); //clear background screen to black - /* glClearColor( 0.5294f * adjust, 0.8078f * adjust, 0.9216f * adjust, 1.0f ); //clear background screen to black */ - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - check_gl(); - - static float id[MAT4_ELEMS] = { 0 }; - static float view[MAT4_ELEMS] = { 0 }; - static float view_proj[MAT4_ELEMS] = { 0 }; - static float normal_matrix[MAT4_ELEMS] = { 0 }; - static float model_view[MAT4_ELEMS] = { 0 }; - static float depth_mvp[MAT4_ELEMS] = { 0 }; - mat4_id(id); - mat4_id(model_view); - - mat4 *mvp = res->test_mvp; - mat4 *projection = config->projection; - mat4 *light = res->light_dir; - - struct node *camera_node = get_node(&config->camera); - assert(camera_node); - - const mat4 *camera = camera_node->mat; - u32 num_entities; - - struct entity *entities = - get_all_entities(&num_entities, NULL); - - struct gpu_program *program = NULL; - - mat4_inverse((float*)camera, view); - mat4_multiply(projection, view, view_proj); - - if (config->is_depth_pass) { - glDisable(GL_CULL_FACE); - mat4_multiply(bias_matrix, view_proj, config->depth_vp); - } - else { - glCullFace(GL_BACK); - } - - mat4_inverse((float *)camera, view); - mat4_multiply(projection, view, view_proj); - - struct model *skybox_model = get_model(&res->skybox.model_id); - assert(skybox_model); - - glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_model->texture); - check_gl(); - - for (u32 i = 0; i < num_entities; ++i) { - struct entity *entity = &entities[i]; - struct model *model = get_model(&entity->model_id); - assert(model); - struct node *node = get_node(&entity->node_id); - assert(node); - - if (entity->flags & ENT_INVISIBLE) - continue; - - if (config->is_depth_pass && !(entity->flags & ENT_CASTS_SHADOWS)) - continue; - - program = &game->test_resources.programs[model->shader]; - - glUseProgram(program->handle); - check_gl(); - - uniform_3f(program, UNIFORM_CAMERA_POSITION, &camera[M_X]); - - if (model->shader == CHESS_PIECE_PROGRAM) { - uniform_1i(program, UNIFORM_IS_WHITE, - (entity->flags & ENT_IS_WHITE) == ENT_IS_WHITE); - } - - uniform_1i(program, UNIFORM_FOG_ON, res->fog_on); - uniform_3f(program, UNIFORM_LIGHT_DIR, light); - uniform_1f(program, UNIFORM_LIGHT_INTENSITY, res->light_intensity); - uniform_1f(program, UNIFORM_SKY_INTENSITY, sky_intensity); - uniform_3f(program, UNIFORM_SUN_COLOR, res->sun_color); - - mat4_multiply(view_proj, node->mat, mvp); - mat4_copy(node->mat, model_view); - mat4_multiply(config->depth_vp, model_view, depth_mvp); - uniform_m4f(program, UNIFORM_DEPTH_MVP, depth_mvp); - uniform_m4f(program, UNIFORM_MVP, mvp); - uniform_m4f(program, UNIFORM_MODEL, node->mat); - - recalc_normals(program->uniforms[UNIFORM_NORMAL_MATRIX].location, - model_view, normal_matrix); - check_gl(); - - struct geometry *geo = get_geometry(&model->geom_id); - /* debug("geo node %s\n", node->label); */ - assert(geo); - render_geometry(geo, program->vertex_attrs, program); - check_gl(); - } - - if (game->wireframe) { - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else { - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - - if (!config->is_depth_pass) { - mat4_inverse((float*)camera, view); - mat4_remove_translations(view); - mat4_multiply(projection, view, view_proj); - - render_skybox(&res->skybox, view_proj); - } - - if (config->draw_ui) - render_ui(&game->ui, view); - - //player - // y tho - - // terrain - - /* glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); */ - /* glUniformMatrix4fv(res->uniforms.model_view, 1, 0, id); */ - /* glUniformMatrix4fv(res->uniforms.world, 1, 0, id); */ - /* glUniformMatrix4fv(res->uniforms.normal_matrix, 1, 0, id); */ - /* recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); */ - /* render_geom(res, geom, GL_TRIANGLES); */ - /* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); */ - /* render_geom(res, geom, GL_TRIANGLES); */ -} diff --git a/src/render.h b/src/render.h @@ -3,8 +3,8 @@ #include "geometry.h" #include "node.h" - -struct game; +#include "mat4.h" +#include "util.h" struct render_config { int draw_ui; @@ -14,10 +14,38 @@ struct render_config { float* depth_vp; }; -void init_gl(struct resources *resources, int width, int height); -void render (struct game *game, struct render_config *config); +void init_gl(); +void recalc_normals(GLint nm_uniform, mat4 *model_view, mat4 *normal); void wireframe_mode_on(); void wireframe_mode_off(); +static inline void uniform_3f(struct gpu_program *program, + enum uniform_id id, const float *v3) +{ + glUniform3f(program->uniforms[id].location, v3[0], v3[1], v3[2]); + check_gl(); +} + +static inline void uniform_1i(struct gpu_program *program, + enum uniform_id id, int i) +{ + glUniform1i(program->uniforms[id].location, i); + check_gl(); +} + +static inline void uniform_m4f(struct gpu_program *program, + enum uniform_id id, float *m) +{ + glUniformMatrix4fv(program->uniforms[id].location, 1, 0, m); + check_gl(); +} + +static inline void uniform_1f(struct gpu_program *program, + enum uniform_id id, float f) +{ + glUniform1f(program->uniforms[id].location, f); + check_gl(); +} + #endif /* POLYADVENT_RENDER_H */ diff --git a/src/scene.c b/src/scene.c @@ -1,91 +1 @@ - -#include "game.h" -#include "model.h" -#include "procmesh.h" -#include "debug.h" -#include "vec3.h" -#include <assert.h> - -void reset_scene(struct game *game) { - struct entity *terrain_ent = get_terrain_entity(&game->terrain); - struct entity *player_ent = get_player(&game->test_resources); - - destroy_entities(); - - // hide terrain and player by default - terrain_ent->flags |= ENT_INVISIBLE; - player_ent->flags |= ENT_INVISIBLE; -} - -void default_scene(struct game *game) { - struct terrain *terrain = &game->terrain; - struct entity *terrain_ent = get_terrain_entity(terrain); - struct entity *player = get_player(&game->test_resources); - - // show terrain - terrain_ent->flags &= ~ENT_INVISIBLE; - - // show player - player->flags &= ~ENT_INVISIBLE; - - struct entity *tower = new_entity(NULL); - struct node *tnode = get_node(&tower->node_id); - - assert(tnode); - tower->model_id = get_model_by_name("tower", NULL); - node_set_label(tnode, "tower"); - //node_attach(&tower->node_id, &player->node_id); - node_translate(tnode, V3(0.0, 50.0, 0.0)); - node_recalc(tnode); - float z = terrain->fn(terrain, tnode->mat[M_X], tnode->mat[M_Y]); - /* node_detach(tnode, pnode); */ - tnode->mat[M_Z] = z; - // END ENTITIES - - -} - - - -void entity_test_scene(struct game *game) -{ - struct terrain *terrain = &game->terrain; - - struct model_id rock_model; - init_id(&rock_model.id); - - /* model_id rock_model = get_static_model(model_tower, NULL); */ - struct model *pmodel = new_model(&rock_model); assert(pmodel); - struct geometry *geom = get_geometry(&pmodel->geom_id); assert(geom); - proc_sphere(geom); - - for (int i = 0; i < 200; i++) { - struct entity *ent = new_entity(NULL); - struct node *node = get_node(&ent->node_id); - - ent->model_id = rock_model; - - double x = rand_0to1() * terrain->size; - double y = rand_0to1() * terrain->size; - double z = terrain->fn(terrain, x, y); - - node_scale(node, pow(15.0, rand_0to1())); - node_rotate(node, V3(rand_0to1(),rand_0to1(),rand_0to1())); - node_translate(node, V3(x, y, z)); - node_set_label(node, "rock"); - - node_recalc(node); - } - -} - -void pbr_scene(struct game *game) -{ - struct entity *ent = new_entity(NULL); - struct node *node = get_node(&ent->node_id); assert(node); - struct entity *player = get_player(&game->test_resources); - - ent->model_id = get_model_by_name("icosphere", NULL); - node_set_label(node, "sphere"); -} diff --git a/src/scene.h b/src/scene.h @@ -4,10 +4,4 @@ #include "game.h" -void default_scene(struct game *); -void reset_scene(struct game *); -void entity_test_scene(struct game *); -void pbr_scene(struct game *); -void chess_scene(struct game *); - #endif /* SCENE_H */ diff --git a/src/shader.c b/src/shader.c @@ -247,7 +247,7 @@ int reload_program(struct gpu_program *program, time_t new_mtime = file_mtime(shader->includes[j]); changed |= include_mtime != new_mtime; } - + changes[i] = changed; if (changed) { @@ -336,4 +336,3 @@ int make_program_from_shaders(const char *name, struct shader **shaders, return 1; } - diff --git a/src/test_game.c b/src/test_game.c @@ -0,0 +1,779 @@ +#include "debug.h" +#include "test_game.h" +#include "camera.h" +#include "entity.h" +#include "orbit_util.h" +#include "game.h" +#include "node.h" +#include "render.h" +#include "quat.h" +#include "movement.h" +#include "gpu.h" +#include "terrain_collision.h" +#include "orbit_util.h" +#include "mat_util.h" +#include "procmesh.h" + +static const float bias_matrix[] = { + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0 +}; + +static void resize_fbos(struct entity *player, struct fbo *shadow_buffer, + float *m4_ortho, int width, int height) +{ + if (shadow_buffer->handle) { + // TODO: remove once delete_fbo deletes attachments + glDeleteTextures(1, &shadow_buffer->attachments[1]); + glDeleteRenderbuffers(1, &shadow_buffer->attachments[0]); + delete_fbo(shadow_buffer); + } + + // TODO: compute better bounds based + const float factor = 40.5; + + struct model *model = get_model(&player->model_id); assert(model); + struct geometry *geom = get_geometry(&model->geom_id); assert(geom); + + float left = geom->min[0] - factor; + float right = geom->max[0] + factor; + float bottom = geom->min[1] - factor; + float top = geom->max[1] + factor; + + /* float left = -factor; */ + /* float right = factor; */ + /* float bottom = factor; */ + /* float top = -factor; */ + + const float near = -50.0; + const float far = 50.0; + + // default ortho screenspace projection + mat4_ortho(left, right, bottom, top, near, far, m4_ortho); + + create_fbo(shadow_buffer, width, height ); + /* fbo_attach_renderbuffer(&res->shadow_buffer, GL_DEPTH24_STENCIL8, */ + /* GL_DEPTH_STENCIL_ATTACHMENT); */ + + /* fbo_attach_color_texture(&res->shadow_buffer); */ + fbo_attach_depth_texture(shadow_buffer); + + check_fbo(shadow_buffer); + + /* fbo_attach_texture(&res->shadow_buffer, GL_DEPTH_COMPONENT16, */ + /* GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */ +} + + +static struct entity *get_player(struct test_game *res) { + struct entity *player = get_entity(&res->player_id); + assert(player); + return player; +} + +static struct entity *get_terrain_entity(struct terrain *t) { + struct entity *ent = get_entity(&t->entity_id); + assert(ent); + return ent; +} + +static void player_movement(struct game *engine, struct entity *player) { + /* if (player->flags & ENT_ON_GROUND) */ + /* entity_movement(game, player); */ + struct node *node = get_node(&player->node_id); + movement(engine, node, 2.0); +} + +static void camera_keep_above_ground(struct terrain *terrain, + struct node *camera) { + if (get_entity(&terrain->entity_id)->flags & ENT_INVISIBLE) + return; + float move[3]; + float *camworld = node_world(camera); + float pen = 0.0; + static const float penlim = 1.0; + struct tri *tri = collide_terrain(terrain, camworld, move, &pen); + + if (!tri) + return; + + if (pen < penlim) { + float dir[3], above[3]; + vec3_normalize(move, dir); + vec3_scale(dir, pen < 0 ? penlim : -penlim, above); + vec3_add(camworld, move, camworld); + vec3_add(camworld, above, camworld); + /* vec3_add(move, above, move); */ + /* vec3_add(camworld, move, camworld); */ + } +} + +static void entity_movement(struct game *game, struct entity *ent) +{ + static const float move_accel = 1.0f; + static const float max_speed = 10.0f; + struct node *node = get_node(&ent->node_id); + + float vel[3]; + + float amt = 10.0 * game->dt; + + if (game->input.keystates[SDL_SCANCODE_W]) { + vec3_forward(ent->velocity, node->orientation, V3(0,amt,0), vel); + if (vec3_lengthsq(vel) <= max_speed*max_speed) + vec3_copy(vel, ent->velocity); + } +} + + +static void player_terrain_collision(struct terrain *terrain, struct node *node) { + // player movement + static vec3 last_pos[3] = {0}; + + if (!vec3_approxeq(node->pos, last_pos)) { + float player_z = node->pos[2]; + + float terrain_z = + terrain->fn(terrain, node->pos[0], node->pos[1]); + + float inset = + min(0.0, player_z - terrain_z); + + if (inset <= 0) + node_translate(node, V3(0.0, 0.0, -inset)); + } + +} + +// TODO: match based on some real concept of time +static void day_night_cycle(float time, struct test_game *res) { + float val = time * 0.0001; + float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ + struct entity *player = get_player(res); + struct node *pnode = get_node(&player->node_id); + assert(pnode); + struct node *suncam = get_node(&res->sun_camera_id); + assert(suncam); + + float light_pos[3]; + + float g = 0.6; + float b = 0.4; + res->sun_color[0] = 1.0; + res->sun_color[1] = g+intensity*(1.0-g); + res->sun_color[2] = b+intensity*(1.0-b); + + /* res->sun_color[0] = 1.0; */ + /* res->sun_color[1] = 1.0; */ + /* res->sun_color[2] = 1.0; */ + + /* vec3_scale(res->sun_color, res->light_intensity, gtmp); */ + + /* float intensity = angle <= 0.5 */ + /* ? clamp(roots, darkest, 1.0) */ + /* : clamp(-roots * 0.4, darkest, 0.5); */ + + res->light_intensity = intensity; + + /* vec3_normalize(res->light_intensity, res->light_intensity); */ + + res->light_dir[0] = 0.0; + /* res->light_dir[1] = sin(val); */ + /* res->light_dir[2] = cos(val) + 1.0; */ + res->light_dir[1] = 0.8; + res->light_dir[2] = 0.8; + + vec3_normalize(res->light_dir, res->light_dir); + + /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ + /* n, res->light_dir[1], res->light_dir[2]); */ + + vec3_add(pnode->pos, res->light_dir, light_pos); + + /* float target[3]; */ + /* float hh = player->model.geom.max[2] / 2.0; */ + /* vec3_copy(player->node.pos, target); */ + /* target[2] += 2.0; */ + + look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat); + /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */ +} + +static void player_update(struct game *engine, struct test_game *game, struct entity *player) +{ + struct orbit *camera = &game->orbit_camera; + struct node *node = get_node(&player->node_id); + struct node *cam_node = get_node(&game->camera_node_id); + assert(node); + assert(cam_node); + + orbit_update_from_mouse(camera, &engine->input,engine->user_settings.mouse_sens, + player, engine->dt); + + camera_keep_above_ground(&game->terrain, cam_node); + + // move player camera toward camera orientation + if (input_is_dragging(&engine->input, SDL_BUTTON_RIGHT)) { + float yaw = game->orbit_camera.coords.azimuth; + quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation); + } + + struct terrain *terrain = &game->terrain; + + player_terrain_collision(terrain, node); + + float move[3]; + float pos[3]; + float pen = 0.0; + vec3_copy(node_world(node), pos); + /* debug("node_world(player) %f %f %f\n", pos[0], pos[1], pos[2]); */ + struct tri *tri = collide_terrain(terrain, pos, move, &pen); + //struct tri *tri = NULL; + /* node_translate(node, move); */ + + if (tri) { + if (vec3_eq(move, V3(0,0,0), 0.1)) { + player->flags |= ENT_ON_GROUND; + } + else if (pen < 0) { + node_translate(node, move); + /* vec3_all(player->velocity, 0); */ + vec3_scale(player->velocity, 0.1, player->velocity); + } + else { + player->flags &= ~ENT_ON_GROUND; + } + } + else { + static int tric = 0; + /* debug("%d no tri\n", tric++); */ + } + + if (player->flags & ENT_ON_GROUND && + (was_key_pressed_this_frame(engine, SDL_SCANCODE_SPACE) /*|| + was_button_pressed_this_frame(engine, SDL_CONTROLLER_BUTTON_X)*/)) { + entity_jump(player, 2.0); + } + + /* debug("player velocity %f %f %f\n", */ + /* player->velocity[0], */ + /* player->velocity[1], */ + /* player->velocity[2]); */ + +// if (player->flags & ENT_AT_REST) +// vec3_scale(player->velocity, 0.00001, player->velocity); + + node_translate(node, player->velocity); + node_recalc(node); +} + + +void init_test_gl(struct test_game *game, struct gpu *gpu, int width, int height) +{ + struct shader vertex, terrain_vertex, chess_piece_vertex, terrain_geom, fragment, fragment_smooth; + struct shader terrain_teval, terrain_tc; + float tmp_matrix[16]; + int ok = 0; + + + // Shaders + ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), + &vertex); + rtassert(ok, "vertex-color shader"); + + ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"), &terrain_vertex); + rtassert(ok, "terrain vertex shader"); + check_gl(); + + ok = make_shader(GL_VERTEX_SHADER, SHADER("chess-piece.v.glsl"), &chess_piece_vertex); + rtassert(ok, "chess-piece vertex shader"); + check_gl(); + + ok = make_shader(GL_FRAGMENT_SHADER, SHADER("main.f.glsl"), &fragment); + rtassert(ok, "default fragment shader"); + check_gl(); + + // camera + mat4_perspective(90 /* fov */, + (float)width / height, + 1, + 5000, + game->proj_persp); + + struct gpu_program *programs = gpu->programs; + struct gpu_program *program; + + ok = make_program("terrain", &terrain_vertex, &fragment, + &programs[TERRAIN_PROGRAM]); + // TODO: replace rtassert with error reporting/handling + rtassert(ok, "terrain program"); + check_gl(); + + ok = make_program("vertex-color", &vertex, &fragment, &programs[DEFAULT_PROGRAM]); + rtassert(ok, "vertex-color program"); + check_gl(); + + program = &programs[CHESS_PIECE_PROGRAM]; + ok = make_program("chess-piece", &chess_piece_vertex, &fragment, program); + rtassert(ok, "chess-piece program"); + + find_uniforms(programs); +} + + +void init_gpu_programs(struct gpu *gpu) +{ +} + + +void render_test_game(struct game *game, struct test_game *res, struct render_config *config) { + float gtmp[3]; + + glEnable(GL_DEPTH_TEST); + + float sky_intensity = clamp(res->light_intensity, 0.2, 1.0); + vec3_scale(res->sun_color, sky_intensity, gtmp); + + glClearColor( gtmp[0], gtmp[1], gtmp[2], 1.0 ); //clear background screen to black + /* glClearColor( 0.5294f * adjust, 0.8078f * adjust, 0.9216f * adjust, 1.0f ); //clear background screen to black */ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + check_gl(); + + static float id[MAT4_ELEMS] = { 0 }; + static float view[MAT4_ELEMS] = { 0 }; + static float view_proj[MAT4_ELEMS] = { 0 }; + static float normal_matrix[MAT4_ELEMS] = { 0 }; + static float model_view[MAT4_ELEMS] = { 0 }; + static float depth_mvp[MAT4_ELEMS] = { 0 }; + mat4_id(id); + mat4_id(model_view); + + mat4 *mvp = res->test_mvp; + mat4 *projection = config->projection; + mat4 *light = res->light_dir; + + struct node *camera_node = get_node(&config->camera); + assert(camera_node); + + const mat4 *camera = camera_node->mat; + u32 num_entities; + + struct entity *entities = + get_all_entities(&num_entities, NULL); + + struct gpu_program *program = NULL; + + mat4_inverse((float*)camera, view); + mat4_multiply(projection, view, view_proj); + + if (config->is_depth_pass) { + glDisable(GL_CULL_FACE); + mat4_multiply(bias_matrix, view_proj, config->depth_vp); + } + else { + glCullFace(GL_BACK); + } + + mat4_inverse((float *)camera, view); + mat4_multiply(projection, view, view_proj); + + struct model *skybox_model = get_model(&res->skybox.model_id); + assert(skybox_model); + + glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_model->texture); + check_gl(); + + for (u32 i = 0; i < num_entities; ++i) { + struct entity *entity = &entities[i]; + struct model *model = get_model(&entity->model_id); + assert(model); + struct node *node = get_node(&entity->node_id); + assert(node); + + if (entity->flags & ENT_INVISIBLE) + continue; + + if (config->is_depth_pass && !(entity->flags & ENT_CASTS_SHADOWS)) + continue; + + program = &game->gpu.programs[model->shader]; + + glUseProgram(program->handle); + check_gl(); + + uniform_3f(program, UNIFORM_CAMERA_POSITION, &camera[M_X]); + + if (model->shader == CHESS_PIECE_PROGRAM) { + uniform_1i(program, UNIFORM_IS_WHITE, + (entity->flags & ENT_IS_WHITE) == ENT_IS_WHITE); + } + + uniform_1i(program, UNIFORM_FOG_ON, res->fog_on); + uniform_3f(program, UNIFORM_LIGHT_DIR, light); + uniform_1f(program, UNIFORM_LIGHT_INTENSITY, res->light_intensity); + uniform_1f(program, UNIFORM_SKY_INTENSITY, sky_intensity); + uniform_3f(program, UNIFORM_SUN_COLOR, res->sun_color); + + mat4_multiply(view_proj, node->mat, mvp); + mat4_copy(node->mat, model_view); + mat4_multiply(config->depth_vp, model_view, depth_mvp); + uniform_m4f(program, UNIFORM_DEPTH_MVP, depth_mvp); + uniform_m4f(program, UNIFORM_MVP, mvp); + uniform_m4f(program, UNIFORM_MODEL, node->mat); + + recalc_normals(program->uniforms[UNIFORM_NORMAL_MATRIX].location, + model_view, normal_matrix); + check_gl(); + + struct geometry *geo = get_geometry(&model->geom_id); + /* debug("geo node %s\n", node->label); */ + assert(geo); + render_geometry(geo, program->vertex_attrs, program); + check_gl(); + } + + if (game->wireframe) { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + + if (!config->is_depth_pass) { + mat4_inverse((float*)camera, view); + mat4_remove_translations(view); + mat4_multiply(projection, view, view_proj); + + render_skybox(&res->skybox, view_proj); + } + + if (config->draw_ui) + render_ui(&game->ui, view); + + //player + // y tho + + // terrain + + /* glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); */ + /* glUniformMatrix4fv(res->uniforms.model_view, 1, 0, id); */ + /* glUniformMatrix4fv(res->uniforms.world, 1, 0, id); */ + /* glUniformMatrix4fv(res->uniforms.normal_matrix, 1, 0, id); */ + /* recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); */ + /* render_geom(res, geom, GL_TRIANGLES); */ + /* glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); */ + /* render_geom(res, geom, GL_TRIANGLES); */ +} + + +void update_test_game (struct game *engine, struct test_game *game) { + static int toggle_fog = 0; + static int needs_terrain_update = 0; + //struct terrain *terrain = &game->terrain; + struct node *root = get_node(&game->root_id); + struct entity *player = get_player(game); + struct node *pnode = get_node(&player->node_id); + struct node *cam_node = get_node(&game->camera_node_id); + + assert(pnode); + assert(cam_node); + + float *time = &game->time; + float *light = game->light_dir; + + gravity(player, engine->dt); + + if (needs_terrain_update) { + /* update_terrain(terrain); */ + needs_terrain_update = 0; + } + + /* spherical_dir(game->test_resources.camera.coords, camera_dir); */ + /* vec3_scale(camera_dir, -1, camera_dir); */ + + if (engine->input.modifiers & KMOD_ALT && + ideq(&game->camera_node_id, &game->free_camera_id)) + { + struct node *freecam_node = get_node(&game->free_camera_id); + assert(freecam_node); + assert(streq(freecam_node->label, "freecam")); + movement(engine, freecam_node, 1.0); + } else { + player_movement(engine, player); + } + + assert(root->parent_id.generation == 0); + + player_update(engine, game, player); + +#ifdef DEBUG + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_R)) + try_reload_shaders(&engine->gpu); +#endif + + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_F5)) { + engine->wireframe ^= 1; + } + + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_C)) { + printf("light_dir %f %f %f\n", light[0], light[1], light[2]); + } + + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_F)) { + toggle_fog = 1; + } + + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_EQUALS)) { + if (!ideq(&game->camera_node_id, &game->free_camera_id)) { + debug("switching to freecam\n"); + game->camera_node_id = game->free_camera_id; + } + else { + debug("switching to orbitcam\n"); + game->camera_node_id = game->orbit_camera.node_id; + } + } + + if (toggle_fog) { + game->fog_on = !game->fog_on; + toggle_fog = 0; + } + + *time = SDL_GetTicks(); + + day_night_cycle(*time, game); + + node_recalc(root); +} + +void test_game_frame(struct game *engine, struct test_game *game) +{ + static float depth_vp[MAT4_ELEMS]; + mat4_id(depth_vp); + + struct render_config fbo_render_config = { + .draw_ui = 0, + .is_depth_pass = 1, + .camera = game->sun_camera_id, + .projection = game->proj_ortho, + .depth_vp = depth_vp + }; + + struct render_config default_config = { + .draw_ui = 0, + .is_depth_pass = 0, + .camera = game->camera_node_id, + .projection = game->proj_persp, + .depth_vp = depth_vp + }; + + struct entity *player = get_entity(&game->player_id); + if (engine->input.resized_height) { + mat4_perspective(60 /* fov */, + (float)engine->width / (float)engine->height, 0.1, + 10000.0, game->proj_persp); + + resize_fbos(player, &game->shadow_buffer, game->proj_ortho, + engine->width, engine->height); + } + + update_test_game(engine, game); + + struct fbo *fbo = &game->shadow_buffer; + check_fbo(fbo); + bind_fbo(fbo); + /* glDrawBuffer(GL_NONE); */ + + render_test_game(engine, game, &fbo_render_config); + unbind_fbo(&game->shadow_buffer); + render_test_game(engine, game, &default_config); +} + +void init_test_game(struct test_game *game, struct gpu *gpu, int width, int height) +{ + memset(game, 0, sizeof(*game)); + struct terrain *terrain = &game->terrain; + struct entity *player; + + init_test_gl(game, gpu, width, height); + + mat4 *mvp = game->test_mvp; + mat4 *light_dir = game->light_dir; + + init_id(&game->root_id); + init_id(&game->sun_camera_id); + init_id(&game->free_camera_id); + + struct node *root = new_node(&game->root_id); + struct node *sun_camera = new_node(&game->sun_camera_id); + + assert(root->parent_id.generation == 0); + assert(root); + assert(sun_camera); + + const double size = 4000.0; + //double scale = 0.03; + double scale = 0.03; + + create_skybox(&game->skybox, &gpu->programs[SKYBOX_PROGRAM]); + + terrain->settings = (struct perlin_settings){ + .depth = 1, + .freq = scale * 0.08, + .o1 = 2.0, .o1s = 0.5, + .o2 = 4.0, .o2s = 0.25, + .amplitude = 70.0, + .ox = 0, + .oy = 0, + .exp = 5.3, + .scale = scale + }; + + init_terrain(terrain, size); + + /* terrain->samples = load_samples(&seed, &terrain->n_samples); */ + terrain->n_samples = 0; + //create_terrain(terrain, size, game->seed); + load_terrain(terrain); + /* update_terrain(terrain, terrain->cell_size); */ + /* get_entity(&terrain->entity_id)->flags |= ENT_INVISIBLE; */ + + /* node_scale(&game->skybox.node, size/4.0); */ + + mat4_id(mvp); + + game->time = 0; + game->light_intensity = 0.8; + + light_dir[0] = 0.8; + light_dir[1] = 0.8; + light_dir[2] = 0.8; + + game->piece_color[0] = 1.0; + game->piece_color[1] = 1.0; + game->piece_color[2] = 1.0; + + game->sun_color[0] = 0.5; + game->sun_color[1] = 0.6; + game->sun_color[2] = 0.7; + + game->fog_on = 0; + game->diffuse_on = 0; + + node_init(root); + node_init(sun_camera); + new_orbit(&game->orbit_camera); + + node_set_label(root, "root"); + + // ENTITIES + + // player entity + init_id(&game->player_id); + player = new_entity(&game->player_id); + player->flags |= ENT_CASTS_SHADOWS; + struct node *pnode = get_node(&player->node_id); + assert(pnode); + + player->model_id = get_model_by_name("pirate_officer", NULL); + assert(!is_null_id(&player->model_id.id)); + + node_set_label(pnode, "player"); + /* node_rotate(pnode, V3(-5.0,0,0)); */ + node_attach(&player->node_id, &game->root_id); + assert(ideq(&pnode->parent_id, &game->root_id)); + + node_translate(pnode, V3(terrain->size/2.,terrain->size/2.,0.0)); + + // orbit camera + game->orbit_camera.coords.azimuth = -quat_yaw(pnode->orientation) - RAD(90.0); + game->orbit_camera.coords.inclination = RAD(60); + game->orbit_camera.coords.radius = 5.0; + game->camera_node_id = game->orbit_camera.node_id; + + // free camera + struct node *freecam = new_node(&game->free_camera_id); + node_set_label(freecam, "freecam"); + node_attach(&game->free_camera_id, &player->node_id); + quat_axis_angle(V3(1,0,0), -45, freecam->orientation); + node_rotate(freecam, V3(100, 0, 0)); + node_translate(freecam, V3(0,-40,20)); + + // FBO STUFF + init_fbo(&game->shadow_buffer); + resize_fbos(player, &game->shadow_buffer, game->proj_ortho, width, height); + // FBO STUFF END + + // TEXTURES + // END TEXTURES +} + +void default_scene(struct test_game *game) { + struct terrain *terrain = &game->terrain; + struct entity *terrain_ent = get_terrain_entity(terrain); + struct entity *player = get_player(game); + + // show terrain + terrain_ent->flags &= ~ENT_INVISIBLE; + + // show player + player->flags &= ~ENT_INVISIBLE; + + struct entity *tower = new_entity(NULL); + struct node *tnode = get_node(&tower->node_id); + + assert(tnode); + tower->model_id = get_model_by_name("tower", NULL); + node_set_label(tnode, "tower"); + //node_attach(&tower->node_id, &player->node_id); + node_translate(tnode, V3(0.0, 50.0, 0.0)); + node_recalc(tnode); + float z = terrain->fn(terrain, tnode->mat[M_X], tnode->mat[M_Y]); + /* node_detach(tnode, pnode); */ + tnode->mat[M_Z] = z; +} + + + +void entity_test_scene(struct terrain *terrain) +{ + struct model_id rock_model; + init_id(&rock_model.id); + + /* model_id rock_model = get_static_model(model_tower, NULL); */ + struct model *pmodel = new_model(&rock_model); assert(pmodel); + struct geometry *geom = get_geometry(&pmodel->geom_id); assert(geom); + proc_sphere(geom); + + for (int i = 0; i < 200; i++) { + struct entity *ent = new_entity(NULL); + struct node *node = get_node(&ent->node_id); + + ent->model_id = rock_model; + + double x = rand_0to1() * terrain->size; + double y = rand_0to1() * terrain->size; + double z = terrain->fn(terrain, x, y); + + node_scale(node, pow(15.0, rand_0to1())); + node_rotate(node, V3(rand_0to1(),rand_0to1(),rand_0to1())); + node_translate(node, V3(x, y, z)); + node_set_label(node, "rock"); + + node_recalc(node); + } + +} + +void pbr_scene(struct test_game *game) +{ + struct entity *ent = new_entity(NULL); + struct node *node = get_node(&ent->node_id); assert(node); + struct entity *player = get_player(game); + + ent->model_id = get_model_by_name("icosphere", NULL); + node_set_label(node, "sphere"); +} diff --git a/src/test_game.h b/src/test_game.h @@ -0,0 +1,50 @@ +#pragma once + +#include "render.h" +#include "terrain.h" +#include "vbo.h" +#include "fbo.h" +#include "geometry.h" +#include "skybox.h" +#include "orbit.h" +#include "gpu.h" +#include "game.h" + +struct test_game { + struct terrain terrain; + struct vbo vertex_buffer, element_buffer, normal_buffer; + struct fbo shadow_buffer; + + node_id root_id; + entity_id player_id; + struct geometry qh_test; + struct orbit orbit_camera; + node_id free_camera_id; + node_id camera_node_id; + node_id sun_camera_id; + + u32 test_cubemap; + float time; + bool fog_on, diffuse_on; + + struct skybox skybox; + float sun_color[3]; + float piece_color[3]; + float test_mvp[MAT4_ELEMS]; + float light_dir[3]; + float light_intensity; + float proj_persp[MAT4_ELEMS]; + float proj_ortho[MAT4_ELEMS]; +}; + + +void init_test_gl(struct test_game *game, struct gpu *gpu, int width, int height); +void render_test_game(struct game *engine, struct test_game *game, struct render_config *config); +void init_test_game(struct test_game *game, struct gpu *gpu, int width, int height); +void test_game_frame(struct game *engine, struct test_game *game); + +void default_scene(struct test_game *); +void entity_test_scene(struct terrain *); +void pbr_scene(struct test_game *); +void chess_scene(struct test_game *); + diff --git a/src/update.c b/src/update.c @@ -17,93 +17,6 @@ #include <math.h> -static void entity_movement(struct game *game, struct entity *ent) -{ - static const float move_accel = 1.0f; - static const float max_speed = 10.0f; - struct node *node = get_node(&ent->node_id); - - float vel[3]; - - float amt = 10.0 * game->dt; - - if (game->input.keystates[SDL_SCANCODE_W]) { - vec3_forward(ent->velocity, node->orientation, V3(0,amt,0), vel); - if (vec3_lengthsq(vel) <= max_speed*max_speed) - vec3_copy(vel, ent->velocity); - } -} - -static void movement(struct game *game, struct node *node, float speed_mult) -{ - float amt = 3.0 * game->dt; - float turn = 1.0 * game->dt; - - float x_axis = (float)game->input.axis[0] / (float)MAX_AXIS_VALUE; - float y_axis = (float)game->input.axis[1] / (float)MAX_AXIS_VALUE; - - amt *= speed_mult; - - if ((game->input.modifiers & KMOD_SHIFT) /*|| - is_button_down(&game->input, SDL_CONTROLLER_BUTTON_LEFTSTICK)*/) - { - amt *= 20; - } - - // joystick movement - node_forward(node, V3(0,amt*y_axis, 0)); - node_forward(node, V3(amt*x_axis, 0, 0)); - - - if (game->input.keystates[SDL_SCANCODE_A]) - node_forward(node, V3(-amt,0,0)); - - if (game->input.keystates[SDL_SCANCODE_UP]) - node_forward(node, V3(0,0,amt)); - - if (game->input.keystates[SDL_SCANCODE_DOWN]) - node_forward(node, V3(0,0,-amt)); - - if (game->input.keystates[SDL_SCANCODE_D]) - node_forward(node, V3(amt,0,0)); - - if (game->input.keystates[SDL_SCANCODE_W]) - node_forward(node, V3(0,amt,0)); - - if (game->input.keystates[SDL_SCANCODE_S]) - node_forward(node, V3(0,-amt,0)); - - if (game->input.keystates[SDL_SCANCODE_K]) - node_forward(node, V3(0, 0,amt)); - - if (game->input.keystates[SDL_SCANCODE_J]) - node_forward(node, V3(0, 0,-amt)); - - if (game->input.keystates[SDL_SCANCODE_E]) - node_rotate(node, V3(0, 0, turn)); - - if (game->input.keystates[SDL_SCANCODE_Q]) - node_rotate(node, V3(0, 0, -turn)); - - /* if (game->input.keystates[SDL_SCANCODE_DOWN]) */ - /* node_translate(node, V3(0, 0, -amt)); */ - - if (was_key_pressed_this_frame(game, SDL_SCANCODE_P)) { - debug("player %f %f %f quat %f %f %f %f\n", - node->pos[0], - node->pos[1], - node->pos[2], - node->orientation[0], - node->orientation[1], - node->orientation[2], - node->orientation[3] - ); - struct spherical *cam = &game->test_resources.orbit_camera.coords; - debug("camera settings radius %f inc %f azimuth %f\n", - cam->radius, cam->inclination, cam->azimuth); - } -} - static void remap_samples(struct point *points, int n_samples, double size) { @@ -125,408 +38,3 @@ static void remap_samples(struct point *points, int n_samples, } } -static void player_terrain_collision(struct terrain *terrain, struct node *node) { - // player movement - static vec3 last_pos[3] = {0}; - - if (!vec3_approxeq(node->pos, last_pos)) { - float player_z = node->pos[2]; - - float terrain_z = - terrain->fn(terrain, node->pos[0], node->pos[1]); - - float inset = - min(0.0, player_z - terrain_z); - - if (inset <= 0) - node_translate(node, V3(0.0, 0.0, -inset)); - } - -} - -static void player_movement(struct game *game, struct entity *player) { - /* if (player->flags & ENT_ON_GROUND) */ - /* entity_movement(game, player); */ - struct node *node = get_node(&player->node_id); - movement(game, node, 2.0); -} - - -#ifdef DEBUG -static int try_reload_shaders(struct resources *res) { - int ret; - for (int i = 0; i < NUM_PROGRAMS; ++i) { - struct gpu_program *program = &res->programs[i]; - ret = reload_program(program, res->programs); - - if (ret == 2) {} - else if (ret == 1) - printf("reload %s success.\n", program->shaders[0].filename); - else - printf("reload %s failed.\n", program->shaders[0].filename); - - // failure ok, clear any errors - glGetError(); - } - - - - - return ret; -} -#endif - -void resize_fbos(struct entity *player, struct fbo *shadow_buffer, - float *m4_ortho, int width, int height) -{ - if (shadow_buffer->handle) { - // TODO: remove once delete_fbo deletes attachments - glDeleteTextures(1, &shadow_buffer->attachments[1]); - glDeleteRenderbuffers(1, &shadow_buffer->attachments[0]); - delete_fbo(shadow_buffer); - } - - // TODO: compute better bounds based - const float factor = 40.5; - - struct model *model = get_model(&player->model_id); assert(model); - struct geometry *geom = get_geometry(&model->geom_id); assert(geom); - - float left = geom->min[0] - factor; - float right = geom->max[0] + factor; - float bottom = geom->min[1] - factor; - float top = geom->max[1] + factor; - - /* float left = -factor; */ - /* float right = factor; */ - /* float bottom = factor; */ - /* float top = -factor; */ - - const float near = -50.0; - const float far = 50.0; - - // default ortho screenspace projection - mat4_ortho(left, right, bottom, top, near, far, m4_ortho); - - create_fbo(shadow_buffer, width, height ); - /* fbo_attach_renderbuffer(&res->shadow_buffer, GL_DEPTH24_STENCIL8, */ - /* GL_DEPTH_STENCIL_ATTACHMENT); */ - - /* fbo_attach_color_texture(&res->shadow_buffer); */ - fbo_attach_depth_texture(shadow_buffer); - - check_fbo(shadow_buffer); - - /* fbo_attach_texture(&res->shadow_buffer, GL_DEPTH_COMPONENT16, */ - /* GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */ - -} - -// TODO: match based on some real concept of time -static void day_night_cycle(float time, struct resources *res) { - float val = time * 0.0001; - float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ - struct entity *player = get_player(res); - struct node *pnode = get_node(&player->node_id); - assert(pnode); - struct node *suncam = get_node(&res->sun_camera_id); - assert(suncam); - - float light_pos[3]; - - float g = 0.6; - float b = 0.4; - res->sun_color[0] = 1.0; - res->sun_color[1] = g+intensity*(1.0-g); - res->sun_color[2] = b+intensity*(1.0-b); - - /* res->sun_color[0] = 1.0; */ - /* res->sun_color[1] = 1.0; */ - /* res->sun_color[2] = 1.0; */ - - /* vec3_scale(res->sun_color, res->light_intensity, gtmp); */ - - /* float intensity = angle <= 0.5 */ - /* ? clamp(roots, darkest, 1.0) */ - /* : clamp(-roots * 0.4, darkest, 0.5); */ - - res->light_intensity = intensity; - - /* vec3_normalize(res->light_intensity, res->light_intensity); */ - - res->light_dir[0] = 0.0; - /* res->light_dir[1] = sin(val); */ - /* res->light_dir[2] = cos(val) + 1.0; */ - res->light_dir[1] = 0.8; - res->light_dir[2] = 0.8; - - vec3_normalize(res->light_dir, res->light_dir); - - /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ - /* n, res->light_dir[1], res->light_dir[2]); */ - - vec3_add(pnode->pos, res->light_dir, light_pos); - - /* float target[3]; */ - /* float hh = player->model.geom.max[2] / 2.0; */ - /* vec3_copy(player->node.pos, target); */ - /* target[2] += 2.0; */ - - look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat); - /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */ -} - -static void gravity(struct game *game) { - struct entity *player = get_player(&game->test_resources); - - if (player->flags & ENT_ON_GROUND) - return; - - struct node *pnode = get_node(&player->node_id); - assert(pnode); - - static const float g = -1.0; - vec3_add(player->velocity, V3(0.0, 0.0, g * game->dt), player->velocity); -} - -void orbit_update_from_mouse(struct orbit *camera, struct input *input, - float mouse_sens, struct entity *player, - float dt) -{ - float target[3]; - struct node *target_node = get_node(&player->node_id); - struct node *cam_node = get_node(&camera->node_id); - struct model *pmodel = get_model(&player->model_id); assert(pmodel); - struct geometry *player_geom = get_geometry(&pmodel->geom_id); assert(player_geom); - - assert(target_node); - assert(cam_node); - - node_recalc(target_node); - vec3_copy(node_world(target_node), target); - assert(player_geom->max[2] != 0); - vec3_add(target, V3(0.0, 0.0, player_geom->max[2]), target); - /* vec3_add(target, V3(0.0, 0.0, 10.0), target); */ - - float mx = 0.0, my = 0.0; - if (input_is_dragging(input, SDL_BUTTON_LEFT) || - input_is_dragging(input, SDL_BUTTON_RIGHT)) { - mx = -input->mdx * mouse_sens * dt; - my = -input->mdy * mouse_sens * dt; - } - - // zoom - if (input->keystates[SDL_SCANCODE_V]) { - if (input->modifiers & KMOD_SHIFT) - camera->coords.radius += dt * 100.0; - else - camera->coords.radius -= dt * 100.0; - - } - else if (input->wheel_y) { - camera->coords.radius += input->wheel_y * dt * 100.0; - } - - camera->coords.radius = max(1.0, camera->coords.radius); - - camera->coords.azimuth += mx; - camera->coords.inclination += my; - - /* - printf("coords azimuth %f inclination %f radius %f\n", - camera->coords.azimuth, - camera->coords.inclination, - camera->coords.radius); - */ - - spherical_look_at(&camera->coords, target, cam_node->mat); - -} - -static void camera_keep_above_ground(struct terrain *terrain, - struct node *camera) { - if (get_entity(&terrain->entity_id)->flags & ENT_INVISIBLE) - return; - float move[3]; - float *camworld = node_world(camera); - float pen = 0.0; - static const float penlim = 1.0; - struct tri *tri = collide_terrain(terrain, camworld, move, &pen); - - if (!tri) - return; - - if (pen < penlim) { - float dir[3], above[3]; - vec3_normalize(move, dir); - vec3_scale(dir, pen < 0 ? penlim : -penlim, above); - vec3_add(camworld, move, camworld); - vec3_add(camworld, above, camworld); - /* vec3_add(move, above, move); */ - /* vec3_add(camworld, move, camworld); */ - } -} - -static void entity_jump(struct entity *ent, float amount) -{ - float dir[3]; - debug("jumping\n"); - vec3_normalize(ent->velocity, dir); - vec3_add(dir, V3(0, 0, amount), dir); - vec3_add(ent->velocity, dir, ent->velocity); -} - -static void player_update(struct game *game, struct entity *player) -{ - - struct resources *res = &game->test_resources; - struct orbit *camera = &res->orbit_camera; - struct node *node = get_node(&player->node_id); - struct node *cam_node = get_node(&res->camera_node_id); - assert(node); - assert(cam_node); - - orbit_update_from_mouse(camera, &game->input, game->user_settings.mouse_sens, - player, game->dt); - - //camera_keep_above_ground(&game->terrain, cam_node); - - // move player camera toward camera orientation - if (input_is_dragging(&game->input, SDL_BUTTON_RIGHT)) { - float yaw = game->test_resources.orbit_camera.coords.azimuth; - quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation); - } - - struct terrain *terrain = &game->terrain; - - /* player_terrain_collision(terrain, node); */ - - float move[3]; - float pos[3]; - float pen = 0.0; - vec3_copy(node_world(node), pos); - /* debug("node_world(player) %f %f %f\n", pos[0], pos[1], pos[2]); */ - //struct tri *tri = collide_terrain(terrain, pos, move, &pen); - struct tri *tri = NULL; - /* node_translate(node, move); */ - - if (tri) { - if (vec3_eq(move, V3(0,0,0), 0.1)) { - player->flags |= ENT_ON_GROUND; - } - else if (pen < 0) { - node_translate(node, move); - /* vec3_all(player->velocity, 0); */ - //vec3_scale(player->velocity, 0.1, player->velocity); - } - else { - player->flags &= ~ENT_ON_GROUND; - } - } - else { - static int tric = 0; - /* debug("%d no tri\n", tric++); */ - } - - if (player->flags & ENT_ON_GROUND && - (was_key_pressed_this_frame(game, SDL_SCANCODE_SPACE) /*|| - was_button_pressed_this_frame(game, SDL_CONTROLLER_BUTTON_X)*/)) { - entity_jump(player, 2.0); - } - - /* debug("player velocity %f %f %f\n", */ - /* player->velocity[0], */ - /* player->velocity[1], */ - /* player->velocity[2]); */ - -// if (player->flags & ENT_AT_REST) -// vec3_scale(player->velocity, 0.00001, player->velocity); - - node_translate(node, player->velocity); - node_recalc(node); -} - - - -void update (struct game *game) { - static int toggle_fog = 0; - static int needs_terrain_update = 0; - struct resources *res = &game->test_resources; - /* struct terrain *terrain = &game->terrain; */ - struct node *root = get_node(&game->test_resources.root_id); - struct entity *player = get_player(res); - struct node *pnode = get_node(&player->node_id); - struct node *cam_node = get_node(&res->camera_node_id); - - assert(pnode); - assert(cam_node); - - float *time = &res->time; - float *light = res->light_dir; - - //gravity(game); - - if (needs_terrain_update) { - /* update_terrain(terrain); */ - needs_terrain_update = 0; - } - - /* spherical_dir(game->test_resources.camera.coords, camera_dir); */ - /* vec3_scale(camera_dir, -1, camera_dir); */ - - if (game->input.modifiers & KMOD_ALT && - ideq(&res->camera_node_id, &res->free_camera_id)) - { - struct node *freecam_node = get_node(&res->free_camera_id); - assert(freecam_node); - assert(streq(freecam_node->label, "freecam")); - movement(game, freecam_node, 1.0); - } - else { - player_movement(game, player); - } - - assert(root->parent_id.generation == 0); - - player_update(game, player); - -#ifdef DEBUG - if (was_key_pressed_this_frame(game, SDL_SCANCODE_R)) - try_reload_shaders(res); -#endif - - if (was_key_pressed_this_frame(game, SDL_SCANCODE_F5)) { - game->wireframe ^= 1; - } - - if (was_key_pressed_this_frame(game, SDL_SCANCODE_C)) { - printf("light_dir %f %f %f\n", light[0], light[1], light[2]); - } - - if (was_key_pressed_this_frame(game, SDL_SCANCODE_F)) - toggle_fog = 1; - - if (was_key_pressed_this_frame(game, SDL_SCANCODE_EQUALS)) { - if (!ideq(&res->camera_node_id, &res->free_camera_id)) { - debug("switching to freecam\n"); - res->camera_node_id = res->free_camera_id; - } - else { - debug("switching to orbitcam\n"); - res->camera_node_id = res->orbit_camera.node_id; - } - } - - if (toggle_fog) { - res->fog_on = !res->fog_on; - toggle_fog = 0; - } - - /* for (int i = 0; i < ) */ - - *time = SDL_GetTicks(); - - day_night_cycle(*time, res); - - node_recalc(root); -} diff --git a/src/update.h b/src/update.h @@ -5,7 +5,10 @@ #include "game.h" void update(struct game * game); +void gravity(struct entity *ent, float dt); void resize_fbos(struct entity *player, struct fbo *shadow_buffer, float *mat4_ortho, int width, int height); +void entity_jump(struct entity *ent, float amount); + #endif /* PA_UPDATE_H */ diff --git a/src/util.h b/src/util.h @@ -7,6 +7,7 @@ #include "mat4.h" #include <assert.h> #include <string.h> +#include <stdio.h> #define check_gl() { \ unsigned int e = glGetError(); \ diff --git a/src/window.c b/src/window.c @@ -7,17 +7,11 @@ #include "update.h" -void -handle_resize(struct game *game, int width, int height) { +void handle_resize(struct game *game, int width, int height) { /* printf("resizing %d %d\n", width, height); */ glViewport( 0, 0, width, height ); - mat4_perspective(60 /* fov */, (float)width / height, 0.1, 10000.0, - game->test_resources.proj_persp); - - resize_fbos(get_entity(&game->test_resources.player_id), - &game->test_resources.shadow_buffer, - game->test_resources.proj_ortho, - width, height); + game->width = width; + game->height = height; /* glMatrixMode( GL_PROJECTION ); //Switch to setting the camera perspective */ /* Set the camera perspective */ diff --git a/test/test_scene.c b/test/test_scene.c @@ -63,7 +63,8 @@ int scene_tests(struct game *game) { t_assert(node_count(root) == initial_node_count, "scene: node count doesn't match initial after reset_scene"); - entity_test_scene(game); + struct terrain *terrain = NULL; + entity_test_scene(game, terrain); get_all_entities(&ent_count, NULL); /* assert(ent_count == 102); */