212 lines
5.1 KiB
Rust
212 lines
5.1 KiB
Rust
use std::{
|
|
convert::TryInto,
|
|
ffi::{
|
|
CString,
|
|
c_void,
|
|
},
|
|
time::Duration,
|
|
};
|
|
|
|
use anyhow::{
|
|
anyhow,
|
|
Context,
|
|
};
|
|
use glam::{
|
|
Mat4,
|
|
Vec3,
|
|
};
|
|
use sdl2::{
|
|
event::Event,
|
|
keyboard::{Keycode, Scancode},
|
|
};
|
|
use tracing::instrument;
|
|
|
|
use opengl_rust::{
|
|
glezz,
|
|
gpu_buffers,
|
|
shader,
|
|
timestep::TimeStep,
|
|
};
|
|
|
|
struct GraphicsContext {
|
|
window: sdl2::video::Window,
|
|
gl_ctx: sdl2::video::GLContext,
|
|
|
|
vertex_buffer: gpu_buffers::VertexBuffer,
|
|
index_buffer: gpu_buffers::IndexBuffer,
|
|
|
|
shader_program: shader::ShaderProgram,
|
|
shader_locations: ShaderLocations,
|
|
}
|
|
|
|
struct ShaderLocations {
|
|
attr_pos: u32,
|
|
attr_color: u32,
|
|
uni_mvp: i32,
|
|
}
|
|
|
|
impl ShaderLocations {
|
|
pub fn new (shader_program: &shader::ShaderProgram) -> anyhow::Result <Self>
|
|
{
|
|
let attr = |name: &str| shader_program.get_attribute_location (&CString::new (name.as_bytes ())?).try_into ().context ("Attribute location negative");
|
|
let uni = |name: &str| shader_program.get_uniform_location (&CString::new (name.as_bytes ())?).try_into ().context ("Uniform location bad");
|
|
|
|
Ok (Self {
|
|
attr_pos: attr ("attr_pos")?,
|
|
attr_color: attr ("attr_color")?,
|
|
uni_mvp: uni ("uni_mvp")?,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[instrument (level = "trace", skip (ctx))]
|
|
fn draw_graphics (ctx: &GraphicsContext) {
|
|
let shader_locs = &ctx.shader_locations;
|
|
let attr_pos = shader_locs.attr_pos;
|
|
let attr_color = shader_locs.attr_color;
|
|
let uni_mvp = shader_locs.uni_mvp;
|
|
|
|
ctx.window.gl_make_current (&ctx.gl_ctx).unwrap ();
|
|
glezz::clear_color (0.392f32, 0.710f32, 0.965f32, 1.0f32);
|
|
glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
|
|
|
let screen_size = (960.0, 540.0);
|
|
|
|
let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), screen_size.0 / screen_size.1, 0.125, 200.0);
|
|
|
|
let view_mat = proj_mat *
|
|
Mat4::from_translation (Vec3::from ((0.0, 0.0, -20.0)));
|
|
|
|
let mvp = view_mat;
|
|
|
|
glezz::uniform_matrix_4fv (uni_mvp, &mvp);
|
|
|
|
ctx.shader_program.use_program ();
|
|
glezz::enable_vertex_attrib_array (Some (attr_pos));
|
|
glezz::enable_vertex_attrib_array (Some (attr_color));
|
|
|
|
ctx.vertex_buffer.bind ();
|
|
ctx.index_buffer.bind ();
|
|
|
|
unsafe {
|
|
let num_quads = 64 * 64;
|
|
let stride = 4 * 6;
|
|
gl::VertexAttribPointer (attr_pos, 3, gl::FLOAT, 0, stride, 0 as *const u8 as *const c_void);
|
|
gl::VertexAttribPointer (attr_color, 3, gl::FLOAT, 0, stride, (4 * 3) as *const u8 as *const c_void);
|
|
|
|
gl::DrawRangeElements (gl::TRIANGLES, 0, num_quads * 4, num_quads as i32 * 6, gl::UNSIGNED_INT, 0 as *const u8 as *const c_void);
|
|
}
|
|
|
|
ctx.window.gl_swap_window ();
|
|
}
|
|
|
|
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 mut vertexes = vec![];
|
|
let mut indexes = vec![];
|
|
let mut start_index = 0;
|
|
|
|
for y in 0..64 {
|
|
for x in 0..64 {
|
|
let (r, g, b) = if (x + y) % 2 == 0 {
|
|
(0.4, 0.4, 0.4)
|
|
}
|
|
else {
|
|
(0.6, 0.6, 0.6)
|
|
};
|
|
|
|
let x = x as f32;
|
|
let y = y as f32;
|
|
let i = start_index;
|
|
|
|
vertexes.extend (&[
|
|
x + 0.0, y + 0.0, 0.0, r, g, b,
|
|
x + 1.0, y + 0.0, 0.0, r, g, b,
|
|
x + 1.0, y + 1.0, 0.0, r, g, b,
|
|
x + 0.0, y + 1.0, 0.0, r, g, b,
|
|
]);
|
|
indexes.extend (&[
|
|
i + 0, i + 1, i + 2,
|
|
i + 0, i + 2, i + 3,
|
|
]);
|
|
start_index += 4;
|
|
}
|
|
}
|
|
|
|
let vertex_buffer = gpu_buffers::VertexBuffer::from_slice (&vertexes);
|
|
let index_buffer = gpu_buffers::IndexBuffer::from_slice_u32 (&indexes);
|
|
|
|
let graphics_ctx = GraphicsContext {
|
|
window,
|
|
gl_ctx,
|
|
|
|
vertex_buffer,
|
|
index_buffer,
|
|
|
|
shader_program,
|
|
shader_locations,
|
|
};
|
|
|
|
'running: loop {
|
|
let frames_to_do = time_step.step ();
|
|
|
|
let _mouse = event_pump.mouse_state ();
|
|
|
|
for event in event_pump.poll_iter() {
|
|
match event {
|
|
Event::Quit {..} |
|
|
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
|
break 'running
|
|
},
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
for _ in 0..frames_to_do {
|
|
|
|
}
|
|
|
|
draw_graphics (&graphics_ctx);
|
|
graphics_frames += 1;
|
|
|
|
std::thread::sleep (Duration::from_millis (15));
|
|
}
|
|
|
|
Ok (())
|
|
}
|