Compare commits

...

6 Commits

Author SHA1 Message Date
a40ba66209 Basic camera movement 2024-09-22 16:00:34 +03:00
9c29ccb8ec Encapsulate dragging logic 2024-09-22 15:53:06 +03:00
24b33f8146 Basic camera control 2024-09-22 15:41:05 +03:00
1d9ff55163 Farther 2024-09-22 15:40:47 +03:00
3d150208e0 kate:build 2024-09-22 15:12:11 +03:00
6012c480de Basic OpenGL 2024-09-22 15:11:08 +03:00
6 changed files with 1159 additions and 19 deletions

18
.kateproject.build Normal file
View File

@ -0,0 +1,18 @@
{
"Auto_generated": "This file is auto-generated. Any extra tags or formatting will be lost",
"target_sets": [
{
"cmake_config": "",
"directory": "%B",
"loaded_via_cmake": false,
"name": "Cargo",
"targets": [
{
"build_cmd": "cargo build --bin wireframe",
"name": "wireframe",
"run_cmd": "cargo run --bin wireframe"
}
]
}
]
}

936
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@ show-image = "0.14.0"
flo_draw = "0.3.1" flo_draw = "0.3.1"
flo_canvas = "0.3.1" flo_canvas = "0.3.1"
itertools-num = "0.1.3" itertools-num = "0.1.3"
glium = "0.35.0"
winit = "0.30.5"
[dev-dependencies] [dev-dependencies]
approx = "0.5.1" approx = "0.5.1"

200
src/bin/wireframe/main.rs Normal file
View File

@ -0,0 +1,200 @@
use glam::{mat4, vec2, vec3, vec4, Mat4, Quat, Vec2, Vec3};
use glium::{
backend::glutin::SimpleWindowBuilder,
implement_vertex, uniform,
winit::event::{Event, WindowEvent},
Program, Surface, VertexBuffer,
};
use winit::{event::ElementState, event_loop::EventLoop};
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 3],
}
implement_vertex!(Vertex, position);
struct DragCtl<S> {
state: S,
ctl: Option<(Vec2, S)>,
}
impl<S: Copy> DragCtl<S> {
pub fn new(state: S) -> Self {
Self { state, ctl: None }
}
pub fn state(&self) -> S {
self.state
}
pub fn on_button(&mut self, pos: Vec2, state: ElementState) {
match state {
ElementState::Pressed => {
assert!(self.ctl.is_none());
self.ctl = Some((pos, self.state));
}
ElementState::Released => {
assert!(self.ctl.is_some());
self.ctl = None;
}
}
}
pub fn on_move(&mut self, pos: Vec2, f: impl FnOnce(S, Vec2) -> S) {
if let Some((old_pos, old_state)) = self.ctl {
self.state = f(old_state, pos - old_pos);
}
}
}
fn main() {
let event_loop = EventLoop::builder().build().unwrap();
let (window, display) = SimpleWindowBuilder::new()
.with_title("Refraction: Wireframe")
.build(&event_loop);
let vs_src = include_str!("ray.v.glsl");
let fs_src = include_str!("ray.f.glsl");
let program = Program::from_source(&display, vs_src, fs_src, None).unwrap();
let indices = glium::index::NoIndices(glium::index::PrimitiveType::LineLoop);
let shape = vec![
Vertex {
position: [-1., 0., 4.],
},
Vertex {
position: [0., -1., 4.],
},
Vertex {
position: [1., 0., 4.],
},
Vertex {
position: [0., 1., 4.],
},
];
let vertex_buffer = VertexBuffer::new(&display, &shape).unwrap();
let mut cur_pos = vec2(0., 0.);
let mut cam_pos = DragCtl::new(Vec3::ZERO);
let mut cam_rot = DragCtl::new(Quat::IDENTITY);
#[allow(deprecated)]
event_loop
.run(move |ev, window_target| match ev {
Event::WindowEvent { event, .. } => match event {
WindowEvent::RedrawRequested => {
let size = window.inner_size();
let size = vec2(size.width as f32, size.height as f32).normalize()
* std::f32::consts::SQRT_2;
let proj = make_proj_matrix(vec3(size.x, size.y, 2.), (0.125, 1024.125));
let view =
Mat4::from_quat(cam_rot.state()) * Mat4::from_translation(cam_pos.state());
let mut target = display.draw();
target.clear_color(0.0, 0.0, 0.2, 1.0);
let mvp = proj * view;
let uniforms = uniform! {
mvp: mvp.to_cols_array_2d(),
};
target
.draw(
&vertex_buffer,
&indices,
&program,
&uniforms,
&Default::default(),
)
.unwrap();
target.finish().unwrap();
}
WindowEvent::MouseInput {
device_id: _,
state,
button,
} => match button {
winit::event::MouseButton::Left => cam_pos.on_button(cur_pos, state),
winit::event::MouseButton::Right => cam_rot.on_button(cur_pos, state),
_ => {}
},
WindowEvent::CursorMoved {
device_id: _,
position,
} => {
let size = window.inner_size();
let size = vec2(size.width as f32, size.height as f32);
cur_pos = vec2(position.x as f32, position.y as f32) / size.length();
cam_pos.on_move(cur_pos, |init, off| {
window.request_redraw();
init + 4. * (cam_rot.state().inverse() * vec3(off.x, -off.y, 0.))
});
cam_rot.on_move(cur_pos, |init, off| {
window.request_redraw();
Quat::from_euler(glam::EulerRot::YXZ, 5. * off.x, 5. * off.y, 0.) * init
});
}
WindowEvent::Resized(window_size) => {
display.resize(window_size.into());
}
WindowEvent::CloseRequested => {
window_target.exit();
}
_ => (),
},
Event::AboutToWait => {
window.request_redraw();
}
_ => (),
})
.unwrap();
}
/// Make a projection matrix, assuming input coordinates are (right, up, forward).
///
/// `corner` is a vector that will be mapped to (x=1, y=1) after the perspective division.
/// `zrange` is the Z range that will be mapped to z∈[-1, 1]. It has no other effect. Both ends have to be positive though.
fn make_proj_matrix(corner: Vec3, zrange: (f32, f32)) -> Mat4 {
let scale = 1.0 / corner;
let zspan = zrange.1 - zrange.0;
mat4(
scale.x * vec4(1., 0., 0., 0.),
scale.y * vec4(0., 1., 0., 0.),
scale.z * vec4(0., 0., (zrange.0 + zrange.1) / zspan, 1.),
scale.z * vec4(0., 0., -2. * zrange.0 * zrange.1 / zspan, 0.),
)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
use glam::vec3;
#[test]
fn test_proj_matrix() {
let m = make_proj_matrix(vec3(2., 3., 4.), (0.5, 20.0));
let v = m * vec4(2., 3., 4., 1.);
assert_abs_diff_eq!(v.x / v.w, 1.0);
assert_abs_diff_eq!(v.y / v.w, 1.0);
assert!(-v.w < v.z && v.z < v.w, "z out of range in {v}");
let v = m * vec4(2., 3., 0.5, 1.);
assert_abs_diff_eq!(v.x / v.w, 8.0);
assert_abs_diff_eq!(v.y / v.w, 8.0);
assert_abs_diff_eq!(v.z / v.w, -1.0);
let v = m * vec4(2., 3., 20.0, 1.);
assert_abs_diff_eq!(v.x / v.w, 0.2);
assert_abs_diff_eq!(v.y / v.w, 0.2);
assert_abs_diff_eq!(v.z / v.w, 1.0);
}
}

View File

@ -0,0 +1,9 @@
#version 330
in vec3 vertex_color;
out vec4 color;
void main() {
color = vec4(vertex_color, 1.0);
}

View File

@ -0,0 +1,13 @@
#version 330
uniform mat4 mvp;
uniform vec3 color;
in vec3 position;
out vec3 vertex_color;
void main() {
vertex_color = color;
gl_Position = mvp * vec4(position, 1.0);
}