void scotland_update() { camera* cam = entity_get("camera"); light* sun = entity_get("sun"); static_object* skydome = entity_get("skydome"); landscape* world = entity_get("world"); sun_orbit += frame_time() * 0.01; sun->position.x = 512 + sin(sun_orbit) * 512; sun->position.y = cos(sun_orbit) * 512; sun->position.z = 512; sun->target = vec3_new(512, 0, 512); if (w_held || s_held) { vec3 cam_dir = vec3_normalize(vec3_sub(cam->target, cam->position)); float speed = 0.5; if (!freecam) speed = 0.05; if (w_held) { cam->position = vec3_add(cam->position, vec3_mul(cam_dir, speed)); } if (s_held) { cam->position = vec3_sub(cam->position, vec3_mul(cam_dir, speed)); } if (!freecam) { float height = terrain_height(asset_hndl_ptr(world->terrain), vec2_new(cam->position.x, cam->position.z)); cam->position.y = height + 1; } cam->target = vec3_add(cam->position, cam_dir); } Uint8 keystate = SDL_GetMouseState(NULL, NULL); if(keystate & SDL_BUTTON(1)){ float a1 = -(float)mouse_x * 0.005; float a2 = (float)mouse_y * 0.005; vec3 cam_dir = vec3_normalize(vec3_sub(cam->target, cam->position)); cam_dir.y += -a2; vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); cam_dir = vec3_add(cam_dir, vec3_mul(side_dir, -a1)); cam_dir = vec3_normalize(cam_dir); cam->target = vec3_add(cam->position, cam_dir); } mouse_x = 0; mouse_y = 0; ui_button* framerate = ui_elem_get("framerate"); ui_button_set_label(framerate, frame_rate_string()); }
void camera_control_freecam(camera* c, float timestep) { const Uint8* kbstate = SDL_GetKeyboardState(NULL); if (kbstate[SDL_SCANCODE_W] || kbstate[SDL_SCANCODE_S] || kbstate[SDL_SCANCODE_A] || kbstate[SDL_SCANCODE_D]) { vec3 cam_dir = vec3_normalize(vec3_sub(c->target, c->position)); vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); const float speed = 100 * timestep; if (kbstate[SDL_SCANCODE_W]) { c->position = vec3_add(c->position, vec3_mul(cam_dir, speed)); c->target = vec3_add(c->target, vec3_mul(cam_dir, speed)); } if (kbstate[SDL_SCANCODE_S]) { c->position = vec3_sub(c->position, vec3_mul(cam_dir, speed)); c->target = vec3_sub(c->target, vec3_mul(cam_dir, speed)); } if (kbstate[SDL_SCANCODE_D]) { c->position = vec3_add(c->position, vec3_mul(side_dir, speed)); c->target = vec3_add(c->target, vec3_mul(side_dir, speed)); } if (kbstate[SDL_SCANCODE_A]) { c->position = vec3_sub(c->position, vec3_mul(side_dir, speed)); c->target = vec3_sub(c->target, vec3_mul(side_dir, speed)); } } int mouse_x, mouse_y; Uint8 mstate = SDL_GetRelativeMouseState(&mouse_x, &mouse_y); if (mstate & SDL_BUTTON(1)) { float a1 = -(float)mouse_x * 0.005; float a2 = (float)mouse_y * 0.005; vec3 cam_dir = vec3_normalize(vec3_sub(c->target, c->position)); cam_dir.y += -a2; vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); cam_dir = vec3_add(cam_dir, vec3_mul(side_dir, -a1)); cam_dir = vec3_normalize(cam_dir); c->target = vec3_add(c->position, cam_dir); } }
static int vec3_mt_mul(lua_State *L) { if (lua_isnumber(L, 1)) { lua_Number a = lua_tonumber(L, 1); vec3_t *b = (vec3_t *)luaL_checkudata(L, 2, "vec3"); return vec3_new(L, a * b->x, a * b->y, a * b->z); } else if (lua_isnumber(L, 2)) { vec3_t *a = (vec3_t *)luaL_checkudata(L, 1, "vec3"); lua_Number b = lua_tonumber(L, 2); return vec3_new(L, a->x * b, a->y * b, a->z * b); } else { return luaL_error(L, "expected arg #1 or #2 to be `number'"); } }
void camera_control_joyorbit(camera* c, float timestep) { if (joystick_count() == 0) return; SDL_Joystick* mainstick = joystick_get(0); int x_move = SDL_JoystickGetAxis(mainstick, 0); int y_move = SDL_JoystickGetAxis(mainstick, 1); /* Dead Zone */ if (abs(x_move) < 10000) { x_move = 0; }; if (abs(y_move) < 10000) { y_move = 0; }; float a1 = (x_move / 32768.0) * -0.05; float a2 = (y_move / 32768.0) * 0.05; vec3 translation = c->target; c->position = vec3_sub(c->position, translation); c->target = vec3_sub(c->target, translation); c->position = mat3_mul_vec3(mat3_rotation_y( a1 ), c->position ); vec3 axis = vec3_normalize(vec3_cross( vec3_sub(c->position, c->target) , vec3_new(0,1,0) )); c->position = mat3_mul_vec3(mat3_rotation_axis_angle(axis, a2 ), c->position ); c->position = vec3_add(c->position, translation); c->target = vec3_add(c->target, translation); }
vec3 terrain_normal(terrain* ter, vec2 position) { mat3 axis = terrain_axis(ter, position); return mat3_mul_vec3(axis, vec3_new(0, 1, 0)); }
void camera_control_orbit(camera* c, SDL_Event e) { float a1 = 0; float a2 = 0; vec3 axis; vec3 translation = c->target; c->position = vec3_sub(c->position, translation); c->target = vec3_sub(c->target, translation); switch(e.type) { case SDL_MOUSEMOTION: if (e.motion.state & SDL_BUTTON(1)) { a1 = e.motion.xrel * -0.005; a2 = e.motion.yrel * 0.005; c->position = mat3_mul_vec3(mat3_rotation_y( a1 ), c->position ); axis = vec3_normalize(vec3_cross( vec3_sub(c->position, c->target) , vec3_new(0,1,0) )); c->position = mat3_mul_vec3(mat3_rotation_angle_axis(a2, axis), c->position ); } break; case SDL_MOUSEWHEEL: c->position = vec3_add(c->position, vec3_mul(vec3_normalize(c->position), -e.wheel.y)); break; } c->position = vec3_add(c->position, translation); c->target = vec3_add(c->target, translation); }
void render_game(struct GameMemory *memory, struct Renderer *renderer, uint32 screen_width, uint32 screen_height) { struct GameState *game_state = (struct GameState *)memory->game_memory; struct RenderBuffer *render_buffer = (struct RenderBuffer *)memory->render_memory; float aspect_ratio = (float)screen_width / (float)screen_height; mat4 projection_matrix = mat4_orthographic(-game_state->camera.zoom/2.0f, game_state->camera.zoom/2.0f, -game_state->camera.zoom/2.0f / aspect_ratio, game_state->camera.zoom/2.0f / aspect_ratio, 0.0f, 1.0f); mat4 view_matrix = mat4_look_at(vec3_new(game_state->camera.position.x, game_state->camera.position.y, 0.0f), vec3_new(game_state->camera.position.x, game_state->camera.position.y, -1.0f), vec3_new(0, 1, 0)); mat4 view_projection_matrix = mat4_mul(projection_matrix, view_matrix); update_ubo(renderer->camera_ubo, sizeof(mat4), &view_projection_matrix); bind_program(renderer->line_program); draw_world_line_buffer(renderer, render_buffer, renderer->line_program); bind_program(0); bind_program(renderer->quad_program); draw_world_quad_buffer(&renderer->sprite_batch, render_buffer); bind_program(0); draw_buildings(game_state, renderer); draw_ships(game_state, renderer); draw_projectiles(game_state, renderer); view_projection_matrix = mat4_orthographic(0, screen_width, screen_height, 0, 0, 1); update_ubo(renderer->camera_ubo, sizeof(mat4), &view_projection_matrix); bind_program(renderer->quad_program); draw_screen_quad_buffer(&renderer->sprite_batch, render_buffer); bind_program(0); draw_frame_text_buffer(renderer, render_buffer); }
static int vec3_index_cross(lua_State *L) { vec3_t *a = (vec3_t *)luaL_checkudata(L, 1, "vec3"); vec3_t *b = (vec3_t *)luaL_checkudata(L, 2, "vec3"); return vec3_new(L, a->y * b->z - a->z * b->y, a->z * b->x - a->x * b->z, a->x * b->y - a->y * b->x); }
mat3 terrain_axis(terrain* ter, vec2 position) { float offset = terrain_height(ter, position); float offset_x = terrain_height(ter, vec2_add(position, vec2_new(1,0))); float offset_y = terrain_height(ter, vec2_add(position, vec2_new(0,1))); vec3 pos = vec3_new(position.x+0, offset, position.y+0); vec3 pos_xv = vec3_new(position.x+1, offset_x, position.y+0); vec3 pos_yv = vec3_new(position.x+0, offset_y, position.y+1); vec3 tangent = vec3_normalize(vec3_sub(pos_xv, pos)); vec3 binorm = vec3_normalize(vec3_sub(pos_yv, pos)); vec3 normal = vec3_cross(binorm, tangent); return mat3_new( tangent.x, tangent.y, tangent.z, normal.x, normal.y, normal.z, binorm.x, binorm.y, binorm.z); }
static int load_resources(void* unused) { folder_load(P("./resources/terrain/")); folder_load(P("./resources/vegetation/")); static_object* skydome = entity_new("skydome", static_object); skydome->renderable = asset_hndl_new_load(P("./resources/terrain/skydome.obj")); ((renderable*)asset_hndl_ptr(skydome->renderable))->material = asset_hndl_new_load(P("$CORANGE/shaders/skydome.mat")); skydome->position = vec3_new(512, 0, 512); skydome->scale = vec3_new(1024, 1024, 1024); landscape* world = entity_new("world", landscape); world->terrain = asset_hndl_new_load(P("./resources/terrain/heightmap.raw")); world->normalmap = asset_hndl_new_load(P("./resources/terrain/normalsmap.dds")); world->colormap = asset_hndl_new_load(P("./resources/terrain/colormap.dds")); world->attributemap = asset_hndl_new_load(P("./resources/terrain/attributemap.dds")); landscape_set_textures(world, asset_hndl_new_load(P("./resources/terrain/surface.dds")), asset_hndl_new_load(P("./resources/terrain/surface_bump.dds")), asset_hndl_new_load(P("./resources/terrain/surface_far.dds")), asset_hndl_new_load(P("./resources/terrain/surface_far_bump.dds"))); vegetation_init(); //vegetation_add_type(asset_get("./resources/terrain/heightmap.raw"), // asset_get("./resources/vegetation/grass.obj"), // 4.0); ui_button* loading = ui_elem_get("loading"); ui_spinner* load_spinner = ui_elem_get("load_spinner"); ui_button* framerate = ui_elem_get("framerate"); ui_button* wireframe = ui_elem_get("wireframe"); ui_button* freecam = ui_elem_get("freecam"); loading->active = false; load_spinner->active = false; framerate->active = true; wireframe->active = true; freecam->active = true; loading_resources = false; return 1; }
static int vec3_new(lua_State *L) { lua_Number x, y, z; if (lua_gettop(L) == 0) { x = y = z = 0; } else { x = luaL_checknumber(L, 1); y = luaL_checknumber(L, 2); z = luaL_checknumber(L, 3); } return vec3_new(L, x, y, z); }
camera* camera_new() { camera* c = malloc(sizeof(camera)); c->position = vec3_new(10, 10, 10); c->target = vec3_zero(); c->fov = 0.785398163; c->near_clip = 0.1; c->far_clip = 512.0; return c; }
static void draw_ships(struct GameState *game_state, struct Renderer *renderer) { bind_program(renderer->quad_program); begin_sprite_batch(&renderer->sprite_batch); for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; draw_quad(&renderer->sprite_batch, ship->position, ship->size, vec3_new(0.5f, 0.5f, 0.5f)); } end_sprite_batch(&renderer->sprite_batch); bind_program(0); }
static void draw_projectiles(struct GameState *game_state, struct Renderer *renderer) { bind_program(renderer->quad_program); begin_sprite_batch(&renderer->sprite_batch); for (uint32 i = 0; i < game_state->projectile_count; ++i) { struct Projectile *projectile = &game_state->projectiles[i]; draw_quad(&renderer->sprite_batch, projectile->position, projectile->size, vec3_new(0.0f, 1.0f, 0.0f)); } end_sprite_batch(&renderer->sprite_batch); bind_program(0); }
static void draw_buildings(struct GameState *game_state, struct Renderer *renderer) { bind_program(renderer->quad_program); begin_sprite_batch(&renderer->sprite_batch); for (uint32 i = 0; i < game_state->building_count; ++i) { struct Building *building = &game_state->buildings[i]; draw_quad(&renderer->sprite_batch, building->position, building->size, vec3_new(0.3f, 0.3f, 0.3f)); } end_sprite_batch(&renderer->sprite_batch); bind_program(0); }
void camera_control_orbit(camera* c, SDL_Event e) { float a1 = 0; float a2 = 0; vec3 axis; vec3 translation = c->target; c->position = vec3_sub(c->position, translation); c->target = vec3_sub(c->target, translation); switch(e.type) { case SDL_MOUSEMOTION: if (e.motion.state & SDL_BUTTON(1)) { a1 = e.motion.xrel * -0.005; a2 = e.motion.yrel * 0.005; c->position = mat3_mul_vec3(mat3_rotation_y( a1 ), c->position ); axis = vec3_normalize(vec3_cross( vec3_sub(c->position, c->target) , vec3_new(0,1,0) )); c->position = mat3_mul_vec3(mat3_rotation_axis_angle(axis, a2 ), c->position ); } break; case SDL_MOUSEBUTTONDOWN: if (e.button.button == SDL_BUTTON_WHEELUP) { c->position = vec3_sub(c->position, vec3_normalize(c->position)); } if (e.button.button == SDL_BUTTON_WHEELDOWN) { c->position = vec3_add(c->position, vec3_normalize(c->position)); } break; } c->position = vec3_add(c->position, translation); c->target = vec3_add(c->target, translation); }
vec3 vec3_gravity() { return vec3_new(0, -9.81, 0); }
void scotland_init() { graphics_viewport_set_dimensions(1280, 720); graphics_viewport_set_title("Scotland"); ui_button* loading = ui_elem_new("loading", ui_button); ui_button_move(loading, vec2_new(graphics_viewport_width() / 2 - 40,graphics_viewport_height() / 2 - 13)); ui_button_resize(loading, vec2_new(80,25)); ui_button_set_label(loading, "Loading..."); ui_button_disable(loading); ui_spinner* load_spinner = ui_elem_new("load_spinner", ui_spinner); load_spinner->color = vec4_white(); load_spinner->top_left = vec2_new(graphics_viewport_width() / 2 + 50, graphics_viewport_height() / 2 - 13); load_spinner->bottom_right = vec2_add(load_spinner->top_left, vec2_new(24,24)); ui_button* framerate = ui_elem_new("framerate", ui_button); ui_button_move(framerate, vec2_new(10,10)); ui_button_resize(framerate, vec2_new(30,25)); ui_button_set_label(framerate, "FRAMERATE"); ui_button_disable(framerate); framerate->active = false; ui_button* wireframe = ui_elem_new("wireframe", ui_button); ui_button_move(wireframe, vec2_new(50,10)); ui_button_resize(wireframe, vec2_new(80,25)); ui_button_set_label(wireframe, "wireframe"); wireframe->active = false; ui_elem_add_event("wireframe", toggle_wireframe); ui_button* freecam = ui_elem_new("freecam", ui_button); ui_button_move(freecam, vec2_new(140,10)); ui_button_resize(freecam, vec2_new(65,25)); ui_button_set_label(freecam, "freecam"); freecam->active = false; ui_elem_add_event("freecam", toggle_freecam); loading_resources = true; SDL_Thread* load_thread = SDL_GL_CreateThread(load_resources, NULL); /* New Camera and light */ camera* cam = entity_new("camera", camera); cam->position = vec3_new(512.0, 200.0, 512.0); cam->target = vec3_new(0.0, 0.0, 0.0); light* sun = entity_new("sun", light); light_set_type(sun, light_type_sun); sun->position = vec3_new(0, 512, 0); sun->target = vec3_new(512, 0, 512); /* Renderer Setup */ shadow_mapper_init(sun); forward_renderer_init(); forward_renderer_set_camera(cam); forward_renderer_set_shadow_light(sun); forward_renderer_set_shadow_texture( shadow_mapper_depth_texture() ); forward_renderer_add_light(sun); }
void m4x4_scale(mat4x4 *inout,float angle, float r_x, float r_y, float r_z, float x, float y, float z) { m4x4_newRotationScale(inout, angle, vec3_new(r_x, r_y, r_z), x, y, z); }
int main(int argc, char **argv) { #ifdef _WIN32 FILE* ctt = fopen("CON", "w" ); FILE* fout = freopen( "CON", "w", stdout ); FILE* ferr = freopen( "CON", "w", stderr ); #endif corange_init("../../assets_core"); graphics_viewport_set_title("Teapot"); graphics_viewport_set_size(1280, 720); camera* cam = entity_new("camera", camera); cam->position = vec3_new(5, 5, 5); cam->target = vec3_new(0, 0, 0); teapot_shader = asset_hndl_new_load(P("./assets/teapot.mat")); teapot_object = asset_hndl_new_load(P("./assets/teapot.obj")); int running = 1; SDL_Event e = {0}; while(running) { frame_begin(); camera* cam = entity_get("camera"); while(SDL_PollEvent(&e)) { switch(e.type){ case SDL_KEYDOWN: case SDL_KEYUP: if (e.key.keysym.sym == SDLK_ESCAPE) { running = 0; } if (e.key.keysym.sym == SDLK_PRINTSCREEN) { graphics_viewport_screenshot(); } if (e.key.keysym.sym == SDLK_r && e.key.keysym.mod == KMOD_LCTRL) { asset_reload_all(); } break; case SDL_QUIT: running = 0; break; } camera_control_orbit(cam, e); ui_event(e); } ui_update(); glClearColor(0.25, 0.25, 0.25, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); shader_program* shader = material_first_program(asset_hndl_ptr(&teapot_shader)); shader_program_enable(shader); shader_program_set_mat4(shader, "world", mat4_id()); shader_program_set_mat4(shader, "view", camera_view_matrix(cam)); shader_program_set_mat4(shader, "proj", camera_proj_matrix(cam)); shader_program_set_texture(shader, "cube_beach", 0, asset_hndl_new_load(P("$CORANGE/water/cube_sea.dds"))); shader_program_set_vec3(shader, "camera_direction", camera_direction(cam)); renderable* r = asset_hndl_ptr(&teapot_object); for(int i=0; i < r->num_surfaces; i++) { renderable_surface* s = r->surfaces[i]; int mentry_id = min(i, ((material*)asset_hndl_ptr(&r->material))->num_entries-1); material_entry* me = material_get_entry(asset_hndl_ptr(&r->material), mentry_id); glBindBuffer(GL_ARRAY_BUFFER, s->vertex_vbo); shader_program_enable_attribute(shader, "vPosition", 3, 18, (void*)0); shader_program_enable_attribute(shader, "vNormal", 3, 18, (void*)(sizeof(float) * 3)); //shader_program_enable_attribute(shader, "vTangent", 3, 18, (void*)(sizeof(float) * 6)); //shader_program_enable_attribute(shader, "vBinormal", 3, 18, (void*)(sizeof(float) * 9)); //shader_program_enable_attribute(shader, "vTexcoord", 2, 18, (void*)(sizeof(float) * 12)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->triangle_vbo); glDrawElements(GL_TRIANGLES, s->num_triangles * 3, GL_UNSIGNED_INT, (void*)0); shader_program_disable_attribute(shader, "vPosition"); shader_program_disable_attribute(shader, "vNormal"); //shader_program_disable_attribute(shader, "vTangent"); //shader_program_disable_attribute(shader, "vBinormal"); //shader_program_disable_attribute(shader, "vTexcoord"); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); } shader_program_disable(shader); glDisable(GL_DEPTH_TEST); ui_render(); graphics_swap(); frame_end(); } corange_finish(); return 0; }
void m4x4_rotateX(mat4x4 *inout, float a, float s_x, float s_y, float s_z) { m4x4_newRotationScale(inout, a, vec3_new(0,1,0), s_x, s_y, s_z); }
void sea_init() { graphics_viewport_set_dimensions(1280, 720); graphics_viewport_set_title("Sea"); camera* cam = entity_new("camera", camera); cam->position = vec3_new(50.0, 50.0, 50.0); cam->target = vec3_new(0, 5, 0); cam->near_clip = 0.1; light* sun = entity_new("sun", light); light_set_type(sun, light_type_spot); sun->position = vec3_new(20,23,16); sun->ambient_color = vec3_new(0.5, 0.5, 0.5); sun->diffuse_color = vec3_new(1.0, 0.894, 0.811); sun->specular_color = vec3_mul(vec3_new(1.0, 0.894, 0.811), 4); sun->power = 5; light* backlight = entity_new("backlight", light); light_set_type(backlight, light_type_point); backlight->position = vec3_new(-22,10,-13); backlight->ambient_color = vec3_new(0.2, 0.2, 0.2); backlight->diffuse_color = vec3_new(0.729, 0.729, 1.0); backlight->specular_color = vec3_mul(vec3_new(0.729, 0.729, 1.0), 1); backlight->power = 2; shadow_mapper_init(sun); forward_renderer_init(); forward_renderer_set_camera(cam); forward_renderer_set_shadow_light(sun); forward_renderer_set_shadow_texture( shadow_mapper_depth_texture() ); forward_renderer_add_light(sun); forward_renderer_add_light(backlight); folder_load(P("./resources/")); renderable* r_seaplane = asset_get(P("./resources/seaplane.obj")); r_seaplane->material = asset_hndl_new(P("./resources/seaplane.mat")); static_object* s_seaplane = entity_new("seaplane", static_object); s_seaplane->renderable = asset_hndl_new_ptr(r_seaplane); s_seaplane->scale = vec3_new(3,1,3); renderable* r_skydome = asset_get(P("./resources/skydome.obj")); r_skydome->material = asset_hndl_new_load(P("$CORANGE/shaders/skydome.mat")); static_object* skydome = entity_new("skydome", static_object); skydome->renderable = asset_hndl_new_ptr(r_skydome); skydome->position = vec3_new(0, -512, 0); skydome->scale = vec3_new(1024, 1024, 1024); folder_load(P("./resources/corvette/")); renderable* r_corvette = asset_get(P("./resources/corvette/corvette.obj")); r_corvette->material = asset_hndl_new_load(P("./resources/corvette/corvette.mat")); static_object* s_corvette = entity_new("corvette", static_object); s_corvette->renderable = asset_hndl_new_ptr(r_corvette); //s_corvette->collision_body = collision_body_new_mesh(asset_get("./resources/corvette/corvette.col")); s_corvette->scale = vec3_new(1.5, 1.5, 1.5); s_corvette->position = vec3_new(0, 0.5, 0); static_object* center_sphere = entity_new("center_sphere", static_object); center_sphere->position = vec3_new(0, 5, 0); //center_sphere->renderable = asset_get("./resources/ball.obj"); //center_sphere->collision_body = collision_body_new_sphere(sphere_new(v3_zero(), 1.0f)); ui_button* framerate = ui_elem_new("framerate", ui_button); ui_button_move(framerate, vec2_new(10,10)); ui_button_resize(framerate, vec2_new(30,25)); ui_button_set_label(framerate, "FRAMERATE"); ui_button_disable(framerate); }
static void terrain_new_chunk(terrain* ter, int i) { const int SUBDIVISIONS = NUM_TERRAIN_SUBDIVISIONS+1; terrain_chunk* tc = malloc(sizeof(terrain_chunk)); tc->id = i; tc->x = i % ter->num_cols; tc->y = i / ter->num_cols; tc->width = ter->chunk_width; tc->height = ter->chunk_height; int x_max = tc->width * SUBDIVISIONS + 1; int y_max = tc->height * SUBDIVISIONS + 1; tc->num_verts = x_max * y_max + x_max * 2 + y_max * 2; vec3* vertex_buffer = malloc(sizeof(vec3) * 4 * tc->num_verts); int index = 0; for(int x = 0; x < x_max; x++) for(int y = 0; y < y_max; y++) { float gx = tc->x * ter->chunk_width + (float)x/SUBDIVISIONS; float gy = tc->y * ter->chunk_height + (float)y/SUBDIVISIONS; float height = terrain_height(ter, vec2_new(gx, gy)); mat3 axis = terrain_tbn(ter, vec2_new(gx, gy)); vec3 pos = vec3_new(gx, height, gy); vec3 tangent = mat3_mul_vec3(axis, vec3_new(1,0,0)); vec3 normal = mat3_mul_vec3(axis, vec3_new(0,1,0)); vec3 binorm = mat3_mul_vec3(axis, vec3_new(0,0,1)); vertex_buffer[index] = pos; index++; vertex_buffer[index] = normal; index++; vertex_buffer[index] = tangent; index++; vertex_buffer[index] = binorm; index++; } /* Adding fins. Don't look, horrible code */ const float FIN_DEPTH = 5.0; for(int y = 0; y < y_max; y++) { int gx = tc->x * ter->chunk_width + 0; int gy = tc->y * ter->chunk_height + (float)y/SUBDIVISIONS; float height = terrain_height(ter, vec2_new(gx, gy)) - FIN_DEPTH; mat3 axis = terrain_tbn(ter, vec2_new(gx, gy)); vec3 pos = vec3_new(gx, height, gy); vec3 tangent = mat3_mul_vec3(axis, vec3_new(1,0,0)); vec3 normal = mat3_mul_vec3(axis, vec3_new(0,1,0)); vec3 binorm = mat3_mul_vec3(axis, vec3_new(0,0,1)); vertex_buffer[index] = pos; index++; vertex_buffer[index] = normal; index++; vertex_buffer[index] = tangent; index++; vertex_buffer[index] = binorm; index++; } for(int y = 0; y < y_max; y++) { int gx = tc->x * ter->chunk_width + ter->chunk_width; int gy = tc->y * ter->chunk_height + (float)y/SUBDIVISIONS; float height = terrain_height(ter, vec2_new(gx, gy)) - FIN_DEPTH; mat3 axis = terrain_tbn(ter, vec2_new(gx, gy)); vec3 pos = vec3_new(gx, height, gy); vec3 tangent = mat3_mul_vec3(axis, vec3_new(1,0,0)); vec3 normal = mat3_mul_vec3(axis, vec3_new(0,1,0)); vec3 binorm = mat3_mul_vec3(axis, vec3_new(0,0,1)); vertex_buffer[index] = pos; index++; vertex_buffer[index] = normal; index++; vertex_buffer[index] = tangent; index++; vertex_buffer[index] = binorm; index++; } for(int x = 0; x < x_max; x++) { int gx = tc->x * ter->chunk_width + (float)x/SUBDIVISIONS; int gy = tc->y * ter->chunk_height + 0; float height = terrain_height(ter, vec2_new(gx, gy)) - FIN_DEPTH; mat3 axis = terrain_tbn(ter, vec2_new(gx, gy)); vec3 pos = vec3_new(gx, height, gy); vec3 tangent = mat3_mul_vec3(axis, vec3_new(1,0,0)); vec3 normal = mat3_mul_vec3(axis, vec3_new(0,1,0)); vec3 binorm = mat3_mul_vec3(axis, vec3_new(0,0,1)); vertex_buffer[index] = pos; index++; vertex_buffer[index] = normal; index++; vertex_buffer[index] = tangent; index++; vertex_buffer[index] = binorm; index++; } for(int x = 0; x < x_max; x++) { int gx = tc->x * ter->chunk_width + (float)x/SUBDIVISIONS; int gy = tc->y * ter->chunk_height + ter->chunk_height; float height = terrain_height(ter, vec2_new(gx, gy)) - FIN_DEPTH; mat3 axis = terrain_tbn(ter, vec2_new(gx, gy)); vec3 pos = vec3_new(gx, height, gy); vec3 tangent = mat3_mul_vec3(axis, vec3_new(1,0,0)); vec3 normal = mat3_mul_vec3(axis, vec3_new(0,1,0)); vec3 binorm = mat3_mul_vec3(axis, vec3_new(0,0,1)); vertex_buffer[index] = pos; index++; vertex_buffer[index] = normal; index++; vertex_buffer[index] = tangent; index++; vertex_buffer[index] = binorm; index++; } tc->bound.center = vec3_zero(); for (int i = 0; i < index; i+=4) { tc->bound.center = vec3_add(tc->bound.center, vertex_buffer[i]); } tc->bound.center = vec3_div(tc->bound.center, tc->num_verts); tc->bound.radius = 0; for (int i = 0; i < index; i+=4) { tc->bound.radius = max(tc->bound.radius, vec3_dist(tc->bound.center, vertex_buffer[i])); } if (net_is_client()) { glGenBuffers(1, &tc->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, tc->vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * 4 * tc->num_verts, vertex_buffer, GL_STATIC_DRAW); } free(vertex_buffer); if (net_is_client()) { glGenBuffers(NUM_TERRAIN_BUFFERS, tc->index_buffers); } for(int j = 0; j < NUM_TERRAIN_BUFFERS; j++) { int off = pow(2, j); int x_max = tc->width * SUBDIVISIONS; int y_max = tc->height * SUBDIVISIONS; tc->num_indicies[j] = (x_max / off) * (y_max / off) * 6 + (x_max / off) * 12 + (y_max / off) * 12; uint32_t* index_buffer = malloc(sizeof(uint32_t) * tc->num_indicies[j]); index = 0; for(int x = 0; x < x_max; x+=off) for(int y = 0; y < y_max; y+=off) { index_buffer[index] = x + y * (x_max+1); index++; index_buffer[index] = (x+off) + y * (x_max+1); index++; index_buffer[index] = (x+off) + (y+off) * (x_max+1); index++; index_buffer[index] = x + y * (x_max+1); index++; index_buffer[index] = (x+off) + (y+off) * (x_max+1); index++; index_buffer[index] = x + (y+off) * (x_max+1); index++; } /* Again, adding fins. Don't look horrible code */ int x_base = (x_max + 1) * (y_max + 1); int y_base = (x_max + 1) * (y_max + 1) + (x_max + 1) * 2; for(int x = 0; x < x_max; x+=off) { index_buffer[index] = x + 0 * (x_max+1); index++; index_buffer[index] = x_base + x; index++; index_buffer[index] = (x+off) + 0 * (x_max+1); index++; index_buffer[index] = (x+off) + 0 * (x_max+1); index++; index_buffer[index] = x_base + x; index++; index_buffer[index] = x_base + x+off; index++; } for(int x = 0; x < x_max; x+=off) { index_buffer[index] = x + y_max * (x_max+1); index++; index_buffer[index] = (x+off) + y_max * (x_max+1); index++; index_buffer[index] = x_base + y_max+1 + x; index++; index_buffer[index] = (x+off) + y_max * (x_max+1); index++; index_buffer[index] = x_base + x_max+1 + x+off; index++; index_buffer[index] = x_base + x_max+1 + x; index++; } for(int y = 0; y < y_max; y+=off) { index_buffer[index] = 0 + y * (x_max+1); index++; index_buffer[index] = 0 + (y+off) * (x_max+1); index++; index_buffer[index] = y_base + y; index++; index_buffer[index] = 0 + (y+off) * (x_max+1); index++; index_buffer[index] = y_base + y+off; index++; index_buffer[index] = y_base + y; index++; } for(int y = 0; y < y_max; y+=off) { index_buffer[index] = x_max + y * (x_max+1); index++; index_buffer[index] = y_base + y_max+1 + y; index++; index_buffer[index] = x_max + (y+off) * (x_max+1); index++; index_buffer[index] = x_max + (y+off) * (x_max+1); index++; index_buffer[index] = y_base + y_max+1 + y; index++; index_buffer[index] = y_base + y_max+1 + y+off; index++; } if (net_is_client()) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tc->index_buffers[j]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * tc->num_indicies[j], index_buffer, GL_DYNAMIC_DRAW); } free(index_buffer); } tc->colmesh = malloc(sizeof(cmesh)); tc->colmesh->is_leaf = true; tc->colmesh->triangles_num = (tc->width/4) * (tc->height/4) * 2; tc->colmesh->triangles = malloc(sizeof(ctri) * tc->colmesh->triangles_num); int tri_i = 0; for (int x = 0; x < tc->width; x += 4) for (int y = 0; y < tc->height; y += 4) { float gx = tc->x * ter->chunk_width + (float)x; float gy = tc->y * ter->chunk_height + (float)y; vec3 a = vec3_new(gx , terrain_height(ter, vec2_new(gx , gy )) , gy ); vec3 b = vec3_new(gx+4, terrain_height(ter, vec2_new(gx+4, gy )) , gy ); vec3 c = vec3_new(gx+4, terrain_height(ter, vec2_new(gx+4, gy+4)) , gy+4); vec3 d = vec3_new(gx , terrain_height(ter, vec2_new(gx , gy+4)) , gy+4); vec3 tang = vec3_normalize(vec3_sub(b, a)); vec3 binorm = vec3_normalize(vec3_sub(d, a)); vec3 norm = vec3_cross( binorm, tang ); tc->colmesh->triangles[tri_i] = ctri_new(a, c, b, norm); tri_i++; tc->colmesh->triangles[tri_i] = ctri_new(a, d, c, norm); tri_i++; } tc->colmesh->bound = cmesh_bound(tc->colmesh); /* For some reason this is not working correctly */ cmesh_subdivide(tc->colmesh, 5); ter->chunks[i] = tc; }
static int vec3_mt_sub(lua_State *L) { vec3_t *a = (vec3_t *)luaL_checkudata(L, 1, "vec3"); vec3_t *b = (vec3_t *)luaL_checkudata(L, 2, "vec3"); return vec3_new(L, a->x - b->x, a->y - b->y, a->z - b->z); }
static int vec3_mt_unm(lua_State *L) { vec3_t *v = (vec3_t *)luaL_checkudata(L, 1, "vec3"); return vec3_new(L, -v->x, -v->y, -v->z); }
static int vec3_index_unit(lua_State *L) { vec3_t *v = (vec3_t *)luaL_checkudata(L, 1, "vec3"); lua_Number l = sqrt(v->x*v->x + v->y*v->y + v->z*v->z); return vec3_new(L, v->x / l, v->y / l, v->z / l); }
mat4 camera_view_matrix(camera* c) { return mat4_view_look_at(c->position, c->target, vec3_new(0.0f,1.0f,0.0f) ); }
material* mat_load_file(char* filename) { SDL_RWops* file = SDL_RWFromFile(filename, "r"); if(file == NULL) { error("Cannot load file %s", filename); } material* m = material_new(); material_entry* me = material_add_entry(m); char line[1024]; while(SDL_RWreadline(file, line, 1024)) { if (line[0] == '#') { continue; } if (line[0] == '\r') { continue; } if (line[0] == '\n') { continue; } if (strstr(line, "submaterial")) { /* Skip Empty Submaterials */ if (me->num_items == 0) { continue; } else { me = material_add_entry(m); continue; } } char type[512]; char name[512]; char value[512]; int matches = sscanf(line, "%511s %511s = %511s", type, name, value); if (matches != 3) continue; material_item mi; int type_id; char* end; float f0, f1, f2, f3; if (strcmp(type, "shader") == 0) { mi.as_asset = asset_hndl_new_load(P(value)); type_id = mat_item_shader; } else if (strcmp(type, "texture") == 0) { mi.as_asset = asset_hndl_new_load(P(value)); type_id = mat_item_texture; } else if (strcmp(type, "int") == 0) { mi.as_int = atoi(value); type_id = mat_item_int; } else if (strcmp(type, "float") == 0) { mi.as_float = atof(value); type_id = mat_item_float; } else if (strcmp(type, "vec2") == 0) { f0 = strtod(value, &end); f1 = strtod(end, NULL); mi.as_vec2 = vec2_new(f0, f1); type_id = mat_item_vec2; } else if (strcmp(type, "vec3") == 0) { f0 = strtod(value, &end); f1 = strtod(end, &end); f2 = strtod(end, NULL); mi.as_vec3 = vec3_new(f0, f1, f2); type_id = mat_item_vec3; } else if (strcmp(type, "vec4") == 0) { f0 = strtod(value, &end); f1 = strtod(end, &end); f2 = strtod(end, &end); f3 = strtod(end, NULL); mi.as_vec4 = vec4_new(f0, f1, f2, f3); type_id = mat_item_vec4; } else { error("Unknown material item type '%s'", type); return NULL; } material_entry_add_item(me, name, type_id, mi); } SDL_RWclose(file); material_generate_programs(m); SDL_GL_CheckError(); return m; }
animation* ani_load_file(char* filename) { int state = STATE_LOAD_EMPTY; animation* a = animation_new(); skeleton* base = skeleton_new(); frame* f = NULL; SDL_RWops* file = SDL_RWFromFile(filename, "r"); if(file == NULL) { error("Could not load file %s", filename); } char line[1024]; while(SDL_RWreadline(file, line, 1024)) { if (state == STATE_LOAD_EMPTY) { int version; if (sscanf(line, "version %i", &version) > 0) { if (version != 1) { error("Can't load ani file '%s'. Don't know how to load version %i\n", filename, version); } } if (strstr(line, "nodes")) { state = STATE_LOAD_NODES; } if (strstr(line, "skeleton")) { state = STATE_LOAD_SKELETON; } } else if (state == STATE_LOAD_NODES) { char name[1024]; int id, parent; if (sscanf(line, "%i \"%[^\"]\" %i", &id, name, &parent) == 3) { skeleton_joint_add(base, name, parent); } if (strstr(line, "end")) { state = STATE_LOAD_EMPTY; } } else if (state == STATE_LOAD_SKELETON) { float time; if (sscanf(line, "time %f", &time) == 1) { f = animation_add_frame(a, base->rest_pose); } int id; float x, y, z, rx, ry, rz; if (sscanf(line, "%i %f %f %f %f %f %f", &id, &x, &y, &z, &rx, &ry, &rz) > 0) { f->joint_positions[id] = vec3_new(x, z, y); mat4 rotation = mat4_rotation_euler(rx, ry, rz); mat4 handedflip = mat4_new(1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1); rotation = mat4_mul_mat4(handedflip, rotation); rotation = mat4_mul_mat4(rotation, handedflip); rotation = mat4_transpose(rotation); f->joint_rotations[id] = mat4_to_quat(rotation); } if (strstr(line, "end")) { state = STATE_LOAD_EMPTY; } } } SDL_RWclose(file); skeleton_delete(base); return a; }
void tick_game(struct GameMemory *memory, struct Input *input, uint32 screen_width, uint32 screen_height, float dt) { struct GameState *game_state = (struct GameState *)memory->game_memory; struct RenderBuffer *render_buffer = (struct RenderBuffer *)memory->render_memory; clear_render_buffer(render_buffer); for (uint32 i = 0; i < game_state->visibility_graph.vertex_count; ++i) { vec2 vertex = game_state->visibility_graph.vertices[i]; draw_world_quad_buffered(render_buffer, vertex, vec2_scalar(0.1f), vec4_zero(), vec3_new(0, 1, 1)); } for (uint32 i = 0; i < game_state->visibility_graph.edge_count; ++i) { uint32 *edge = &game_state->visibility_graph.edges[i][0]; vec2 p0 = game_state->visibility_graph.vertices[edge[0]]; vec2 p1 = game_state->visibility_graph.vertices[edge[1]]; draw_world_line_buffered(render_buffer, p0, p1, vec3_new(1, 1, 0)); } if (mouse_down(MOUSE_LEFT, input)) { struct AABB box = calc_mouse_selection_box(input, MOUSE_LEFT); vec2 size = vec2_sub(box.max, box.min); vec2 bottom_left = vec2_new(box.min.x, box.max.y); vec2 bottom_right = vec2_new(box.max.x, box.max.y); vec2 top_left = vec2_new(box.min.x, box.min.y); vec2 top_right = vec2_new(box.max.x, box.min.y); const uint32 outline_thickness = 1; draw_screen_quad_buffered(render_buffer, top_left, vec2_new(size.x, outline_thickness), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, bottom_left, vec2_new(size.x, outline_thickness), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, top_left, vec2_new(outline_thickness, size.y), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, top_right, vec2_new(outline_thickness, size.y), vec4_zero(), vec3_new(1, 1, 0)); } if (mouse_released(MOUSE_LEFT, input)) { // Clear previous selection. game_state->selected_ship_count = 0; struct AABB screen_selection_box = calc_mouse_selection_box(input, MOUSE_LEFT); // Because screen space y-values are inverted, these two results have conflicting // y-values, i.e. screen_to_world_min.y is actually the maximum y. These values // are then properly min/maxed and stored correctly in world_selection_box. vec2 screen_to_world_min = screen_to_world_coords(screen_selection_box.min, &game_state->camera, screen_width, screen_height); vec2 screen_to_world_max = screen_to_world_coords(screen_selection_box.max, &game_state->camera, screen_width, screen_height); struct AABB world_selection_box; world_selection_box.min = min_vec2(screen_to_world_min, screen_to_world_max); world_selection_box.max = max_vec2(screen_to_world_min, screen_to_world_max); // Add colliding ships to the selection list. // TODO: optimize, spatial grid hash? for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; struct AABB ship_aabb = aabb_from_transform(ship->position, ship->size); vec2 center = vec2_div(vec2_add(ship_aabb.min, ship_aabb.max), 2.0f); if (aabb_aabb_intersection(world_selection_box, ship_aabb)) game_state->selected_ships[game_state->selected_ship_count++] = ship->id; } if (game_state->selected_ship_count > 0) fprintf(stderr, "selected %u ships\n", game_state->selected_ship_count); } if (mouse_down(MOUSE_RIGHT, input)) { vec2 target_position = screen_to_world_coords(input->mouse_position, &game_state->camera, screen_width, screen_height); for (uint32 i = 0; i < game_state->selected_ship_count; ++i) { uint32 id = game_state->selected_ships[i]; struct Ship *ship = get_ship_by_id(game_state, id); ship->target_position = target_position; ship->move_order = true; } } // Outline selected ships. for (uint32 i = 0; i < game_state->selected_ship_count; ++i) { uint32 id = game_state->selected_ships[i]; struct Ship *ship = get_ship_by_id(game_state, id); draw_world_quad_buffered(render_buffer, ship->position, vec2_mul(ship->size, 1.1f), vec4_zero(), vec3_new(0, 1, 0)); if (ship->move_order) draw_world_quad_buffered(render_buffer, ship->target_position, vec2_new(0.5f, 0.5f), vec4_zero(), vec3_new(0, 1, 0)); } // Handle move orders. for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; if (ship->move_order) { vec2 direction = vec2_zero(); /* if (vec2_length2(direction) < FLOAT_EPSILON) direction = vec2_normalize(vec2_sub(ship->target_position, ship->position)); */ ship->move_velocity = vec2_mul(direction, 2.0f); /* vec2 direction = vec2_normalize(vec2_sub(ship->target_position, ship->position)); ship->move_velocity = vec2_mul(direction, 2.0f); */ if (vec2_distance2(ship->position, ship->target_position) < 0.1f) { ship->move_velocity = vec2_zero(); ship->move_order = false; } } } tick_camera(input, &game_state->camera, dt); tick_combat(game_state, dt); tick_physics(game_state, dt); }