diff --git a/shaders/terrain-vert.glsl b/shaders/terrain-vert.glsl index 79a628d..6c248b6 100644 --- a/shaders/terrain-vert.glsl +++ b/shaders/terrain-vert.glsl @@ -13,7 +13,7 @@ varying lowp vec3 vary_color; void main (void) { vec3 sun_dir = normalize (vec3 (1.0, 1.0, 4.0)); - vec3 sun_light = vec3 (1.0, 0.75, 0.5) * max (0.0, dot (attr_normal, sun_dir)); + vec3 sun_light = vec3 (1.0, 0.75, 0.5) * sqrt (max (0.0, dot (attr_normal, sun_dir))); vec3 sky_light = vec3 (0.0, 0.25, 0.5) * (attr_normal.z * 0.5 + 0.5); vary_color = sqrt (attr_color * (sun_light + sky_light)); diff --git a/src/bin/terrain.rs b/src/bin/terrain.rs index d1cacde..30abd86 100644 --- a/src/bin/terrain.rs +++ b/src/bin/terrain.rs @@ -19,7 +19,10 @@ use sdl2::{ event::Event, keyboard::{Keycode, Scancode}, }; -use tracing::instrument; +use tracing::{ + debug, + instrument, +}; use opengl_rust::{ glezz, @@ -66,7 +69,8 @@ impl ShaderLocations { } #[instrument (level = "trace", skip (ctx, state))] -fn draw_graphics (ctx: &GraphicsContext, state: &GameState) +fn draw_graphics (ctx: &GraphicsContext, state: &GameState) +-> anyhow::Result <()> { let shader_locs = &ctx.shader_locations; let attr_pos = shader_locs.attr_pos; @@ -85,7 +89,7 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState) let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), screen_size.0 / screen_size.1, 0.125, 200.0); - let spin_period = 360 * 4; + let spin_period = 360 * 8; let view_mat = proj_mat * Mat4::from_translation (Vec3::from ((0.0, 0.0, -80.0))) * @@ -105,6 +109,19 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState) ctx.vertex_buffer.bind (); ctx.index_buffer.bind (); + let bump_period = 360 * 7; + let bump_theta = (state.logic_frames % bump_period) as f32 * 3.1415926535 * 2.0 / bump_period as f32; + + let ClientArrays { + vertexes, + indexes, + } = make_heightmap_arrays (&[ + (32.0, 48.0), + (32.0 + 16.0 * bump_theta.cos (), 32.0 + 16.0 * bump_theta.sin ()), + ]); + + upload_vertexes (&vertexes)?; + unsafe { let num_quads = 64 * 64; let stride = 4 * 9; @@ -116,45 +133,16 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState) } ctx.window.gl_swap_window (); + + Ok (()) } -fn main () -> anyhow::Result <()> { - tracing_subscriber::fmt::fmt () - .with_env_filter (tracing_subscriber::EnvFilter::from_default_env()) - .with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE) - .init (); - - let sdl_context = sdl2::init ().map_err (|e| anyhow! ("Can't init SDL: {}", e))?; - - let video_subsystem = sdl_context.video ().map_err (|e| anyhow! ("Can't get SDL video subsystem: {}", e))?; - let window = video_subsystem.window ("Heightmap terrain demo", 960, 540) - .position_centered () - .opengl () - .build () - ?; - - gl::load_with (|s| { - video_subsystem.gl_get_proc_address (s) as *const _ - }); - - assert! (gl::ClearColor::is_loaded ()); - - let gl_ctx = window.gl_create_context ().map_err (|e| anyhow! ("Can't create OpenGL context: {}", e))?; - - window.gl_make_current (&gl_ctx).map_err (|e| anyhow! ("Can't make OpenGL context current: {}", e))?; - - let mut time_step = TimeStep::new (60, 1000); - - let mut graphics_frames = 0; - - let controller_subsystem = sdl_context.game_controller ().unwrap (); - let controller = controller_subsystem.open (0).ok (); - - let mut event_pump = sdl_context.event_pump ().unwrap (); - - let shader_program = shader::shader_from_files ("shaders/terrain-vert.glsl", "shaders/terrain-frag.glsl"); - let shader_locations = ShaderLocations::new (&shader_program)?; - +struct ClientArrays { + vertexes: Vec , + indexes: Vec , +} + +fn make_heightmap_arrays (bumps: &[(f32, f32)]) -> ClientArrays { let mut vertexes = vec![]; let mut indexes = vec![]; let mut start_index = 0; @@ -163,15 +151,22 @@ fn main () -> anyhow::Result <()> { let x = x - bump_x; let y = y - bump_y; - let d = x * x + y * y; + let d2: f32 = x * x + y * y; + if d2 > 8.0 * 8.0 { + return 0.0; + } + let d = d2.sqrt (); - f32::max (0.0, 5.0 - d * 0.125) + let t = f32::min (1.0, f32::max (0.0, (8.0 - d) / 6.0)); + let z = -2.0 * t * t + 3.0 * t * t; + + f32::max (0.0, 4.0 * z) }; let height_fn = |(x, y)| { - bump_at (32.0, 32.0, x, y) + - bump_at (64.0, 32.0, x, y) + - bump_at (32.0, 48.0, x, y) + bumps.iter () + .map (|(bump_x, bump_y)| bump_at (bump_x, bump_y, x, y)) + .sum () }; for y in 0..64 { @@ -227,9 +222,83 @@ fn main () -> anyhow::Result <()> { } } - let vertex_buffer = gpu_buffers::VertexBuffer::from_slice (&vertexes); + ClientArrays { + vertexes, + indexes, + } +} + +fn upload_vertexes (vertexes: &[f32]) -> anyhow::Result <()> { + unsafe { + gl::BufferSubData ( + gl::ARRAY_BUFFER, + 0, + (vertexes.len () * 4).try_into ()?, + &vertexes [0] as *const f32 as *const c_void + ); + } + + Ok (()) +} + +fn main () -> anyhow::Result <()> { + tracing_subscriber::fmt::fmt () + .with_env_filter (tracing_subscriber::EnvFilter::from_default_env()) + .with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE) + .init (); + + let sdl_context = sdl2::init ().map_err (|e| anyhow! ("Can't init SDL: {}", e))?; + + let video_subsystem = sdl_context.video ().map_err (|e| anyhow! ("Can't get SDL video subsystem: {}", e))?; + let window = video_subsystem.window ("Heightmap terrain demo", 960, 540) + .position_centered () + .opengl () + .build () + ?; + + gl::load_with (|s| { + video_subsystem.gl_get_proc_address (s) as *const _ + }); + + assert! (gl::ClearColor::is_loaded ()); + + let gl_ctx = window.gl_create_context ().map_err (|e| anyhow! ("Can't create OpenGL context: {}", e))?; + + window.gl_make_current (&gl_ctx).map_err (|e| anyhow! ("Can't make OpenGL context current: {}", e))?; + + let mut time_step = TimeStep::new (60, 1000); + + let mut graphics_frames = 0; + + let controller_subsystem = sdl_context.game_controller ().unwrap (); + let controller = controller_subsystem.open (0).ok (); + + let mut event_pump = sdl_context.event_pump ().unwrap (); + + let shader_program = shader::shader_from_files ("shaders/terrain-vert.glsl", "shaders/terrain-frag.glsl"); + let shader_locations = ShaderLocations::new (&shader_program)?; + + let ClientArrays { + vertexes, + indexes, + } = make_heightmap_arrays (&[]); + + debug! ("Floats in vertex buffer: {}", vertexes.len ()); + + let vertex_buffer = gpu_buffers::VertexBuffer::streaming (vertexes.len ()); let index_buffer = gpu_buffers::IndexBuffer::from_slice_u32 (&indexes); + upload_vertexes (&vertexes)?; + + unsafe { + gl::BufferSubData ( + gl::ARRAY_BUFFER, + 0, + (vertexes.len () * 4).try_into ()?, + &vertexes [0] as *const f32 as *const c_void + ); + } + let graphics_ctx = GraphicsContext { window, gl_ctx, @@ -264,7 +333,7 @@ fn main () -> anyhow::Result <()> { game_state.logic_frames += 1; } - draw_graphics (&graphics_ctx, &game_state); + draw_graphics (&graphics_ctx, &game_state)?; graphics_frames += 1; std::thread::sleep (Duration::from_millis (15));