diff options
author | pommicket <pommicket@gmail.com> | 2023-01-22 15:20:30 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2023-01-22 15:20:50 -0500 |
commit | 12cb5d119330d518dc9992c962c4cd748e8ef616 (patch) | |
tree | 0f36d1fd929ffe408e5e22072945eedfb7d466a8 /src | |
parent | 41edf14f207592ff95a7fca502fa49f5c917f967 (diff) |
configurable resolution
Diffstat (limited to 'src')
-rw-r--r-- | src/fshader_post.glsl | 6 | ||||
-rw-r--r-- | src/main.rs | 153 | ||||
-rw-r--r-- | src/sdf.rs | 42 | ||||
-rw-r--r-- | src/sdl.rs | 273 | ||||
-rw-r--r-- | src/vshader_main.glsl | 8 | ||||
-rw-r--r-- | src/vshader_post.glsl | 7 | ||||
-rw-r--r-- | src/vshader_test.glsl | 7 | ||||
-rw-r--r-- | src/win.rs | 299 |
8 files changed, 541 insertions, 254 deletions
diff --git a/src/fshader_post.glsl b/src/fshader_post.glsl new file mode 100644 index 0000000..d7b9100 --- /dev/null +++ b/src/fshader_post.glsl @@ -0,0 +1,6 @@ +uniform sampler2D u_texture; +IN vec2 uv; + +void main() { + gl_FragColor = texture(u_texture, uv); +} diff --git a/src/main.rs b/src/main.rs index fbe9d68..5a40014 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ /* @TODO: -- configurable resolution - (e.g. run on 1080p monitor at 720p to make it go faster) - let user go back&forth through past sdfs using scenes.txt file - documentation - GenRandom integers (just use 0..u32::MAX and add a modulus) @@ -27,7 +25,7 @@ use std::{ io::{prelude::*, BufReader}, time::Instant, }; -use win::{ColorGrayscaleF32, ColorF32}; +use win::{ColorF32, ColorGrayscaleF32, ColorU8}; type Vec3 = Vector3<f32>; type Mat3 = Matrix3<f32>; @@ -41,7 +39,7 @@ enum Icon { Copy = 1, Play = 2, Pause = 3, - Rewind = 4 + Rewind = 4, } #[derive(Clone)] @@ -111,6 +109,7 @@ impl View { struct Programs { main: win::Program, test: win::Program, + post: win::Program, } impl Programs { @@ -118,13 +117,18 @@ impl Programs { Programs { main: window.new_program(), test: window.new_program(), + post: window.new_program(), } } fn load_scene(&mut self, window: &mut win::Window, scene: &sdf::Scene) -> Result<(), String> { - let source_main = include_str!("fshader_main.glsl"); - let source_test = include_str!("fshader_test.glsl"); + let vsource_main = include_str!("vshader_main.glsl"); + let fsource_main = include_str!("fshader_main.glsl"); + let vsource_test = include_str!("vshader_test.glsl"); + let fsource_test = include_str!("fshader_test.glsl"); let source_common = include_str!("fshader_common.glsl"); + let vsource_post = include_str!("vshader_post.glsl"); + let fsource_post = include_str!("fshader_post.glsl"); let mut sdf = String::new(); let mut get_color = String::new(); @@ -132,40 +136,22 @@ impl Programs { scene .color_function .to_glsl_function("get_color_", &mut get_color); - let source_main = source_main + let fsource_main = fsource_main .replace("%SDF%", &sdf) .replace("%COLOR%", &get_color) .replace("%COMMON%", source_common); - let source_test = source_test + let fsource_test = fsource_test .replace("%SDF%", &sdf) .replace("%COMMON%", source_common); window - .link_program( - &mut self.main, - "IN vec2 v_pos; - OUT vec2 pos; - uniform float u_aspect_ratio; - - void main() { - pos = v_pos * vec2(u_aspect_ratio, 1.0); - gl_Position = vec4(v_pos, 0.0, 1.0); - }", - &source_main, - ) + .link_program(&mut self.main, vsource_main, &fsource_main) .map_err(|e| format!("Error compiling shader:\n{e}"))?; window - .link_program( - &mut self.test, - "IN vec2 v_pos; - OUT vec2 pos; - - void main() { - pos = v_pos; - gl_Position = vec4(v_pos, 0.0, 1.0); - }", - &source_test, - ) + .link_program(&mut self.test, vsource_test, &fsource_test) + .map_err(|e| format!("Error compiling shader:\n{e}"))?; + window + .link_program(&mut self.post, vsource_post, &fsource_post) .map_err(|e| format!("Error compiling shader:\n{e}"))?; Ok(()) } @@ -239,10 +225,14 @@ struct State { scene: sdf::Scene, // can be none if opening failed for whatever reason scene_list: Option<File>, - framebuffer_texture: win::Texture, - framebuffer: win::Framebuffer, + test_framebuffer_texture: win::Texture, + test_framebuffer: win::Framebuffer, + main_framebuffer_texture: win::Texture, + main_framebuffer: win::Framebuffer, + main_framebuffer_size: (i32, i32), main_array: win::VertexArray, test_array: win::VertexArray, + post_array: win::VertexArray, // displayed on top of the screen. used for feedback when copying/pasting/etc flash: ColorF32, flash_icon: Icon, @@ -263,23 +253,31 @@ impl State { .load_scene(&mut window, &scene) .unwrap_or_else(|e| eprintln!("Error: {e}")); - let mut framebuffer_texture = window.create_texture(&Default::default()); + let mut test_framebuffer_texture = window.create_texture(&Default::default()); // we don't really care if there's an error. not much bad will happen. - let _ = window.set_texture_no_data::<ColorGrayscaleF32>( - &mut framebuffer_texture, + let _ = test_framebuffer_texture.set_data::<ColorGrayscaleF32>( + None, TEST_WIDTH.into(), TEST_HEIGHT.into(), ); - let mut framebuffer = window.create_framebuffer(); - window.set_framebuffer_texture( - &mut framebuffer, + let mut test_framebuffer = window.create_framebuffer(); + test_framebuffer.set_texture( win::FramebufferAttachment::Color0, - &framebuffer_texture, + &test_framebuffer_texture, ); - + + + let main_texconfig = win::TextureParams { + mag_filter: win::TextureFilter::Nearest, + ..Default::default() + }; + let main_framebuffer_texture = window.create_texture(&main_texconfig); + let main_framebuffer = window.create_framebuffer(); + let mut main_buffer = window.create_buffer(); let mut test_buffer = window.create_buffer(); + let mut post_buffer = window.create_buffer(); let data: &[[f32; 2]] = &[ [-1.0, -1.0], [1.0, -1.0], @@ -288,10 +286,12 @@ impl State { [1.0, 1.0], [-1.0, 1.0], ]; - window.set_buffer_data(&mut main_buffer, data); - window.set_buffer_data(&mut test_buffer, data); + main_buffer.set_data(data); + test_buffer.set_data(data); + post_buffer.set_data(data); let main_array = window.create_vertex_array(main_buffer, &programs.main); let test_array = window.create_vertex_array(test_buffer, &programs.test); + let post_array = window.create_vertex_array(post_buffer, &programs.post); window.set_mouse_relative(true); @@ -311,10 +311,14 @@ impl State { show_debug_info: false, fullscreen: false, scene: sdf::Scene::default(), - framebuffer_texture, - framebuffer, + test_framebuffer_texture, + test_framebuffer, + main_framebuffer_texture, + main_framebuffer, + main_framebuffer_size: (0, 0), main_array, test_array, + post_array, scene_list, settings, flash: ColorF32::rgba(0.0, 0.0, 0.0, 0.0), @@ -336,27 +340,27 @@ impl State { } // *technically speaking* the location of v_pos could change between reloads - self.window.array_attrib2f(&mut self.main_array, "v_pos", 0); - self.window.array_attrib2f(&mut self.test_array, "v_pos", 0); + self.main_array.attrib2f("v_pos", 0); + self.test_array.attrib2f("v_pos", 0); + self.post_array.attrib2f("v_pos", 0); // percentage of space occupied by object let frac = 0.25; // determine default level set // specifically we want to select y such that // for ~frac of p values, sdf(p) < y - self.window.bind_framebuffer(Some(&self.framebuffer)); + self.window.bind_framebuffer(Some(&self.test_framebuffer)); self.window .viewport(0, 0, TEST_WIDTH.into(), TEST_HEIGHT.into()); self.window.use_program(&self.programs.test); - self.window.draw_array(&self.test_array); + self.test_array.draw(); - self.window.viewport_full_screen(); self.window.bind_framebuffer(None); let mut sdf_values: Vec<f32> = self .window - .get_texture_data_vec::<ColorGrayscaleF32>(&self.framebuffer_texture) + .get_texture_data_vec::<ColorGrayscaleF32>(&self.test_framebuffer_texture) .iter() .map(|c| c.value) .collect(); @@ -382,11 +386,21 @@ impl State { self.flash = match icon { Icon::None => ColorF32::BLACK, Icon::Copy => ColorF32::GREEN, - _ => ColorF32::rgb(1.0,0.5,0.0), + _ => ColorF32::rgb(1.0, 0.5, 0.0), }; self.flash_icon = icon; } + fn render_resolution(&self) -> (i32, i32) { + let scale = self.settings.get_f32("scale").unwrap_or(1.0); + if scale <= 0.0 || scale > 1.0 { + win::display_error_message(&format!("bad scale: {scale}")); + std::process::exit(1); + } + let (w, h) = self.window.size(); + ((w as f32 * scale) as i32, (h as f32 * scale) as i32) + } + // returns false if we should quit fn frame(&mut self) -> bool { if let Some(max_framerate) = self.settings.get_f32("max-framerate") { @@ -539,15 +553,32 @@ impl State { self.view.level_set += dl * level_set_amount; } + let render_resolution = self.render_resolution(); + if render_resolution != self.main_framebuffer_size { + let result = self.main_framebuffer_texture.set_data::<ColorU8>(None, render_resolution.0 as usize, render_resolution.1 as usize); + + match result { + Ok(()) => {}, + Err(e) => eprintln!("warning:{e}"), + } + + self.main_framebuffer.set_texture( + win::FramebufferAttachment::Color0, + &self.main_framebuffer_texture, + ); + self.main_framebuffer_size = render_resolution; + } + let window = &mut self.window; let view = &self.view; - window.viewport_full_screen(); + window.viewport(0, 0, render_resolution.0, render_resolution.1); window.clear_screen(win::ColorF32::BLACK); window.use_program(&self.programs.main); - window.uniform1f("u_aspect_ratio", window.aspect_ratio()); + window.bind_framebuffer(Some(&self.main_framebuffer)); + window.uniform1f("u_aspect_ratio", render_resolution.0 as f32 / render_resolution.1 as f32); { - let (w,h) = window.size(); + let (w, h) = window.size(); window.uniform2f("u_screen_size", w as f32, h as f32); } window.uniform1f("u_time", view.time as f32); @@ -575,16 +606,24 @@ impl State { window.uniform3f_slice("u_translation", view.pos.as_slice()); window.uniform4f_color("u_flash", self.flash); window.uniform1i("u_flash_icon", self.flash_icon as i32); - + self.flash.a = f32::max(self.flash.a - frame_dt * (2.0 - 1.0 * self.flash.a), 0.0); if self.flash.a <= 0.0 { // icon is no longer visible self.flash_icon = Icon::None; } - window.draw_array(&self.main_array); + self.main_array.draw(); + + window.bind_framebuffer(None); + window.viewport_full_screen(); + window.use_program(&self.programs.post); + window.active_texture(0, &self.main_framebuffer_texture); + window.uniform_texture("u_texture", 0); + self.post_array.draw(); window.swap(); + if self.show_debug_info { println!("frame time = {:?}ms", frame_dt * 1000.0); } @@ -17,14 +17,12 @@ macro_rules! write_str { #[derive(Copy, Clone)] pub struct SdfParams { - max_depth: i32 + max_depth: i32, } impl Default for SdfParams { fn default() -> Self { - Self { - max_depth: 5 - } + Self { max_depth: 5 } } } @@ -395,9 +393,7 @@ trait Function: Sized + Default + GenRandom<SdfParams> + ImportExport { fn good_random(rng: &mut impl Rng, function_length: usize) -> Self { let default_len = Self::default().export_string().len(); for max_depth in 1.. { - let params = SdfParams { - max_depth - }; + let params = SdfParams { max_depth }; let mut functions = vec![]; for _i in 0..20 { let f = Self::gen_random_params(rng, params); @@ -554,18 +550,9 @@ impl Function for R3ToR3 { let a = var.next(); let theta = var.next(); let output = var.next(); - write_str!( - code, - "vec3 {s} = {input} * {c};\n" - ); - write_str!( - code, - "vec2 {a} = vec2(cos({s}.x), sin({s}.y));\n" - ); - write_str!( - code, - "float {theta} = {s}.z * sqrt(2.0);\n" - ); + write_str!(code, "vec3 {s} = {input} * {c};\n"); + write_str!(code, "vec2 {a} = vec2(cos({s}.x), sin({s}.y));\n"); + write_str!(code, "float {theta} = {s}.z * sqrt(2.0);\n"); write_str!( code, "vec3 {output} = vec3({a}.x*cos({theta})+{a}.y*sin({theta}), @@ -575,18 +562,19 @@ impl Function for R3ToR3 { } Wibbly => { let output = var.next(); - write_str!(code, + write_str!( + code, "vec3 {output} = sqrt({input}*({input}+3*sin({input}))) * 0.39;\n" ); output } Sqrt(c) => { let output = var.next(); - write_str!(code, + write_str!( + code, "vec3 {output} = sqrt({c} * abs({input}) + {c}*{c}) * 2.0;\n" ); output - } } } @@ -650,10 +638,7 @@ impl Function for R3ToR { } Cylinder(x, y) => { let output = var.next(); - write_str!( - code, - "float {output} = sdf_cylinder({input}, {x}, {y});\n" - ); + write_str!(code, "float {output} = sdf_cylinder({input}, {x}, {y});\n"); output } Mix(a, b, t) => { @@ -691,10 +676,7 @@ impl Function for R3ToR { let a = a.to_glsl(input, code, var); let b = b.to_glsl(input, code, var); let output = var.next(); - write_str!( - code, - "float {output} = sin({a}) * cos({b});\n" - ); + write_str!(code, "float {output} = sin({a}) * cos({b});\n"); output } Compose(pre, f, post) => { @@ -3,7 +3,6 @@ #![allow(non_snake_case)] /// this module provides SDL type definitions, and more rust-y wrappers around /// SDL functions. - use std::ffi::{c_char, c_float, c_int, c_void, CStr, CString}; use std::mem; @@ -663,7 +662,6 @@ pub struct SDL_Color { pub type SDL_Colour = SDL_Color; - #[repr(C)] #[derive(Copy, Clone)] pub struct SDL_Rect { @@ -673,7 +671,6 @@ pub struct SDL_Rect { h: c_int, } - #[repr(C)] pub struct SDL_Palette { ncolors: c_int, @@ -786,7 +783,6 @@ impl SDL_AudioSpec { } } - #[link(name = "SDL2", kind = "dylib")] extern "C" { fn SDL_Init(flags: u32) -> c_int; @@ -824,6 +820,8 @@ extern "C" { fn SDL_GL_GetProcAddress(proc: *const c_char) -> *mut c_void; fn SDL_PollEvent(event: *mut SDL_Event) -> c_int; fn SDL_GetKeyboardState(numkeys: *mut c_int) -> *const u8; + fn SDL_GetKeyFromScancode(scancode: SDL_Scancode) -> SDL_Keycode; + // NOTE: do NOT add SDL_GetScancodeFromKey !!! see get_scancodes_from_key for explanation. fn SDL_OpenAudioDevice( device: *const c_char, iscapture: c_int, @@ -1095,12 +1093,262 @@ pub mod scancode { pub const NUM_SCANCODES: SDL_Scancode = 512; } +pub mod keycode { + use super::scancode; + use super::{SDL_Keycode, SDL_Scancode}; + const fn SDL_SCANCODE_TO_KEYCODE(scancode: SDL_Scancode) -> SDL_Keycode { + scancode as SDL_Keycode | 1 << 30 + } + + pub const UNKNOWN: SDL_Keycode = 0; + pub const RETURN: SDL_Keycode = '\r' as _; + pub const ESCAPE: SDL_Keycode = '\x1b' as _; + pub const BACKSPACE: SDL_Keycode = '\x08' as _; + pub const TAB: SDL_Keycode = '\t' as _; + pub const SPACE: SDL_Keycode = ' ' as _; + pub const EXCLAIM: SDL_Keycode = '!' as _; + pub const QUOTEDBL: SDL_Keycode = '"' as _; + pub const HASH: SDL_Keycode = '#' as _; + pub const PERCENT: SDL_Keycode = '%' as _; + pub const DOLLAR: SDL_Keycode = '$' as _; + pub const AMPERSAND: SDL_Keycode = '&' as _; + pub const QUOTE: SDL_Keycode = '\'' as _; + pub const LEFTPAREN: SDL_Keycode = '(' as _; + pub const RIGHTPAREN: SDL_Keycode = ')' as _; + pub const ASTERISK: SDL_Keycode = '*' as _; + pub const PLUS: SDL_Keycode = '+' as _; + pub const COMMA: SDL_Keycode = ',' as _; + pub const MINUS: SDL_Keycode = '-' as _; + pub const PERIOD: SDL_Keycode = '.' as _; + pub const SLASH: SDL_Keycode = '/' as _; + pub const N0: SDL_Keycode = '0' as _; + pub const N1: SDL_Keycode = '1' as _; + pub const N2: SDL_Keycode = '2' as _; + pub const N3: SDL_Keycode = '3' as _; + pub const N4: SDL_Keycode = '4' as _; + pub const N5: SDL_Keycode = '5' as _; + pub const N6: SDL_Keycode = '6' as _; + pub const N7: SDL_Keycode = '7' as _; + pub const N8: SDL_Keycode = '8' as _; + pub const N9: SDL_Keycode = '9' as _; + pub const COLON: SDL_Keycode = ':' as _; + pub const SEMICOLON: SDL_Keycode = ';' as _; + pub const LESS: SDL_Keycode = '<' as _; + pub const EQUALS: SDL_Keycode = '=' as _; + pub const GREATER: SDL_Keycode = '>' as _; + pub const QUESTION: SDL_Keycode = '?' as _; + pub const AT: SDL_Keycode = '@' as _; + pub const LEFTBRACKET: SDL_Keycode = '[' as _; + pub const BACKSLASH: SDL_Keycode = '\\' as _; + pub const RIGHTBRACKET: SDL_Keycode = ']' as _; + pub const CARET: SDL_Keycode = '^' as _; + pub const UNDERSCORE: SDL_Keycode = '_' as _; + pub const BACKQUOTE: SDL_Keycode = '`' as _; + pub const A: SDL_Keycode = 'a' as _; + pub const B: SDL_Keycode = 'b' as _; + pub const C: SDL_Keycode = 'c' as _; + pub const D: SDL_Keycode = 'd' as _; + pub const E: SDL_Keycode = 'e' as _; + pub const F: SDL_Keycode = 'f' as _; + pub const G: SDL_Keycode = 'g' as _; + pub const H: SDL_Keycode = 'h' as _; + pub const I: SDL_Keycode = 'i' as _; + pub const J: SDL_Keycode = 'j' as _; + pub const K: SDL_Keycode = 'k' as _; + pub const L: SDL_Keycode = 'l' as _; + pub const M: SDL_Keycode = 'm' as _; + pub const N: SDL_Keycode = 'n' as _; + pub const O: SDL_Keycode = 'o' as _; + pub const P: SDL_Keycode = 'p' as _; + pub const Q: SDL_Keycode = 'q' as _; + pub const R: SDL_Keycode = 'r' as _; + pub const S: SDL_Keycode = 's' as _; + pub const T: SDL_Keycode = 't' as _; + pub const U: SDL_Keycode = 'u' as _; + pub const V: SDL_Keycode = 'v' as _; + pub const W: SDL_Keycode = 'w' as _; + pub const X: SDL_Keycode = 'x' as _; + pub const Y: SDL_Keycode = 'y' as _; + pub const Z: SDL_Keycode = 'z' as _; + pub const CAPSLOCK: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CAPSLOCK); + pub const F1: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F1); + pub const F2: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F2); + pub const F3: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F3); + pub const F4: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F4); + pub const F5: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F5); + pub const F6: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F6); + pub const F7: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F7); + pub const F8: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F8); + pub const F9: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F9); + pub const F10: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F10); + pub const F11: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F11); + pub const F12: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F12); + pub const PRINTSCREEN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PRINTSCREEN); + pub const SCROLLLOCK: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::SCROLLLOCK); + pub const PAUSE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PAUSE); + pub const INSERT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::INSERT); + pub const HOME: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::HOME); + pub const PAGEUP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PAGEUP); + pub const DELETE: SDL_Keycode = '\x7f' as _; + pub const END: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::END); + pub const PAGEDOWN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PAGEDOWN); + pub const RIGHT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RIGHT); + pub const LEFT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::LEFT); + pub const DOWN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::DOWN); + pub const UP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::UP); + pub const NUMLOCKCLEAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::NUMLOCKCLEAR); + pub const KP_DIVIDE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_DIVIDE); + pub const KP_MULTIPLY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MULTIPLY); + pub const KP_MINUS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MINUS); + pub const KP_PLUS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_PLUS); + pub const KP_ENTER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_ENTER); + pub const KP_1: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_1); + pub const KP_2: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_2); + pub const KP_3: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_3); + pub const KP_4: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_4); + pub const KP_5: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_5); + pub const KP_6: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_6); + pub const KP_7: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_7); + pub const KP_8: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_8); + pub const KP_9: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_9); + pub const KP_0: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_0); + pub const KP_PERIOD: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_PERIOD); + pub const APPLICATION: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::APPLICATION); + pub const POWER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::POWER); + pub const KP_EQUALS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_EQUALS); + pub const F13: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F13); + pub const F14: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F14); + pub const F15: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F15); + pub const F16: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F16); + pub const F17: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F17); + pub const F18: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F18); + pub const F19: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F19); + pub const F20: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F20); + pub const F21: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F21); + pub const F22: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F22); + pub const F23: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F23); + pub const F24: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::F24); + pub const EXECUTE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::EXECUTE); + pub const HELP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::HELP); + pub const MENU: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::MENU); + pub const SELECT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::SELECT); + pub const STOP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::STOP); + pub const AGAIN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AGAIN); + pub const UNDO: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::UNDO); + pub const CUT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CUT); + pub const COPY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::COPY); + pub const PASTE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PASTE); + pub const FIND: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::FIND); + pub const MUTE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::MUTE); + pub const VOLUMEUP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::VOLUMEUP); + pub const VOLUMEDOWN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::VOLUMEDOWN); + pub const KP_COMMA: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_COMMA); + pub const KP_EQUALSAS400: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_EQUALSAS400); + pub const ALTERASE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::ALTERASE); + pub const SYSREQ: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::SYSREQ); + pub const CANCEL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CANCEL); + pub const CLEAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CLEAR); + pub const PRIOR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::PRIOR); + pub const RETURN2: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RETURN2); + pub const SEPARATOR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::SEPARATOR); + pub const OUT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::OUT); + pub const OPER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::OPER); + pub const CLEARAGAIN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CLEARAGAIN); + pub const CRSEL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CRSEL); + pub const EXSEL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::EXSEL); + pub const KP_00: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_00); + pub const KP_000: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_000); + pub const THOUSANDSSEPARATOR: SDL_Keycode = + SDL_SCANCODE_TO_KEYCODE(scancode::THOUSANDSSEPARATOR); + pub const DECIMALSEPARATOR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::DECIMALSEPARATOR); + pub const CURRENCYUNIT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CURRENCYUNIT); + pub const CURRENCYSUBUNIT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CURRENCYSUBUNIT); + pub const KP_LEFTPAREN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_LEFTPAREN); + pub const KP_RIGHTPAREN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_RIGHTPAREN); + pub const KP_LEFTBRACE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_LEFTBRACE); + pub const KP_RIGHTBRACE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_RIGHTBRACE); + pub const KP_TAB: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_TAB); + pub const KP_BACKSPACE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_BACKSPACE); + pub const KP_A: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_A); + pub const KP_B: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_B); + pub const KP_C: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_C); + pub const KP_D: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_D); + pub const KP_E: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_E); + pub const KP_F: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_F); + pub const KP_XOR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_XOR); + pub const KP_POWER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_POWER); + pub const KP_PERCENT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_PERCENT); + pub const KP_LESS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_LESS); + pub const KP_GREATER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_GREATER); + pub const KP_AMPERSAND: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_AMPERSAND); + pub const KP_DBLAMPERSAND: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_DBLAMPERSAND); + pub const KP_VERTICALBAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_VERTICALBAR); + pub const KP_DBLVERTICALBAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_DBLVERTICALBAR); + pub const KP_COLON: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_COLON); + pub const KP_HASH: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_HASH); + pub const KP_SPACE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_SPACE); + pub const KP_AT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_AT); + pub const KP_EXCLAM: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_EXCLAM); + pub const KP_MEMSTORE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMSTORE); + pub const KP_MEMRECALL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMRECALL); + pub const KP_MEMCLEAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMCLEAR); + pub const KP_MEMADD: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMADD); + pub const KP_MEMSUBTRACT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMSUBTRACT); + pub const KP_MEMMULTIPLY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMMULTIPLY); + pub const KP_MEMDIVIDE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_MEMDIVIDE); + pub const KP_PLUSMINUS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_PLUSMINUS); + pub const KP_CLEAR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_CLEAR); + pub const KP_CLEARENTRY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_CLEARENTRY); + pub const KP_BINARY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_BINARY); + pub const KP_OCTAL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_OCTAL); + pub const KP_DECIMAL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_DECIMAL); + pub const KP_HEXADECIMAL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KP_HEXADECIMAL); + pub const LCTRL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::LCTRL); + pub const LSHIFT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::LSHIFT); + pub const LALT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::LALT); + pub const LGUI: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::LGUI); + pub const RCTRL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RCTRL); + pub const RSHIFT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RSHIFT); + pub const RALT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RALT); + pub const RGUI: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::RGUI); + pub const MODE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::MODE); + pub const AUDIONEXT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIONEXT); + pub const AUDIOPREV: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOPREV); + pub const AUDIOSTOP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOSTOP); + pub const AUDIOPLAY: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOPLAY); + pub const AUDIOMUTE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOMUTE); + pub const MEDIASELECT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::MEDIASELECT); + pub const WWW: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::WWW); + pub const MAIL: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::MAIL); + pub const CALCULATOR: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::CALCULATOR); + pub const COMPUTER: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::COMPUTER); + pub const AC_SEARCH: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_SEARCH); + pub const AC_HOME: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_HOME); + pub const AC_BACK: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_BACK); + pub const AC_FORWARD: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_FORWARD); + pub const AC_STOP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_STOP); + pub const AC_REFRESH: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_REFRESH); + pub const AC_BOOKMARKS: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AC_BOOKMARKS); + pub const BRIGHTNESSDOWN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::BRIGHTNESSDOWN); + pub const BRIGHTNESSUP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::BRIGHTNESSUP); + pub const DISPLAYSWITCH: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::DISPLAYSWITCH); + pub const KBDILLUMTOGGLE: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KBDILLUMTOGGLE); + pub const KBDILLUMDOWN: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KBDILLUMDOWN); + pub const KBDILLUMUP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::KBDILLUMUP); + pub const EJECT: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::EJECT); + pub const SLEEP: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::SLEEP); + pub const APP1: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::APP1); + pub const APP2: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::APP2); + pub const AUDIOREWIND: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOREWIND); + pub const AUDIOFASTFORWARD: SDL_Keycode = SDL_SCANCODE_TO_KEYCODE(scancode::AUDIOFASTFORWARD); +} + pub struct Surface { - ptr: *mut SDL_Surface + ptr: *mut SDL_Surface, } impl Surface { - /// Returns `None` if `ptr` is null. + /// Returns `None` if `ptr` is null. /// # Safety /// You may only call this function if `ptr` refers to a valid `SDL_Surface` /// which can be freed with `SDL_FreeSurface`. @@ -1113,7 +1361,7 @@ impl Surface { Some(Self { ptr }) } } - + /// # Safety /// It is your responsibility to use the pointer *before* dropping this `Surface`. pub unsafe fn get_raw(&self) -> *mut SDL_Surface { @@ -1352,3 +1600,14 @@ pub unsafe fn load_bmp(filename: &str) -> Result<Surface, String> { pub unsafe fn set_window_icon(win: *mut SDL_Window, icon: &Surface) { SDL_SetWindowIcon(win, icon.ptr); } + +/// Get all scancodes associated with a keycode. +/// +/// `SDL_GetScancodeFromKey` is a bad function! it's possible (though unlikely) for multiple +/// scancodes to map to the same keycode. i've encountered this problem myself +/// with sdl applications (don't ask why). +pub unsafe fn get_scancodes_from_key(keycode: SDL_Keycode) -> impl Iterator<Item = SDL_Scancode> { + // the current implementation of SDL_GetKeyFromScancode is just an array lookup so this loop + // should perform well. + (0..scancode::NUM_SCANCODES).filter(move |&scn| SDL_GetKeyFromScancode(scn) == keycode) +} diff --git a/src/vshader_main.glsl b/src/vshader_main.glsl new file mode 100644 index 0000000..dad57c3 --- /dev/null +++ b/src/vshader_main.glsl @@ -0,0 +1,8 @@ +IN vec2 v_pos; +OUT vec2 pos; +uniform float u_aspect_ratio; + +void main() { + pos = v_pos * vec2(u_aspect_ratio, 1.0); + gl_Position = vec4(v_pos, 0.0, 1.0); +} diff --git a/src/vshader_post.glsl b/src/vshader_post.glsl new file mode 100644 index 0000000..89e76ff --- /dev/null +++ b/src/vshader_post.glsl @@ -0,0 +1,7 @@ +attribute vec2 v_pos; +OUT vec2 uv; + +void main() { + uv = v_pos * 0.5 + 0.5; + gl_Position = vec4(v_pos, 0.0, 1.0); +} diff --git a/src/vshader_test.glsl b/src/vshader_test.glsl new file mode 100644 index 0000000..fe58014 --- /dev/null +++ b/src/vshader_test.glsl @@ -0,0 +1,7 @@ +IN vec2 v_pos; +OUT vec2 pos; + +void main() { + pos = v_pos; + gl_Position = vec4(v_pos, 0.0, 1.0); +} @@ -10,9 +10,10 @@ use std::{fmt, mem}; pub type AudioCallback = fn(sample_rate: u32, samples: &mut [f32]); -/// dammit rust why wont you stabilize negative_impls +/// adding this type to a struct prevents it from being sent across threads. type NoSendSync = *const u8; +#[repr(C)] struct AudioData { callback: AudioCallback, device: sdl::SDL_AudioDeviceID, @@ -28,6 +29,7 @@ pub struct Window { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Key { + Unknown, A, B, C, @@ -131,12 +133,14 @@ pub enum Key { F10, F11, F12, + Other(u32), } impl Key { - fn from_sdl(scancode: sdl::SDL_Scancode) -> Option<Self> { - use sdl::scancode::*; - Some(match scancode { + fn from_sdl(keycode: sdl::SDL_Keycode) -> Self { + use sdl::keycode::*; + match keycode { + UNKNOWN => Key::Unknown, A => Key::A, B => Key::B, C => Key::C, @@ -232,21 +236,22 @@ impl Key { RIGHTBRACKET => Key::RightBracket, BACKSLASH => Key::Backslash, SEMICOLON => Key::Semicolon, - APOSTROPHE => Key::Quote, + QUOTE => Key::Quote, COMMA => Key::Comma, PERIOD => Key::Period, SLASH => Key::Slash, - GRAVE => Key::Backtick, + BACKQUOTE => Key::Backtick, BACKSPACE => Key::Backspace, TAB => Key::Tab, CAPSLOCK => Key::CapsLock, - _ => return None, - }) + x => Key::Other(x), + } } - fn to_sdl(self) -> sdl::SDL_Scancode { - use sdl::scancode::*; + fn to_sdl(self) -> sdl::SDL_Keycode { + use sdl::keycode::*; match self { + Key::Unknown => UNKNOWN, Key::A => A, Key::B => B, Key::C => C, @@ -294,8 +299,8 @@ impl Key { Key::Comma => COMMA, Key::Period => PERIOD, Key::Slash => SLASH, - Key::Quote => APOSTROPHE, - Key::Backtick => GRAVE, + Key::Quote => QUOTE, + Key::Backtick => BACKQUOTE, Key::Backspace => BACKSPACE, Key::Up => UP, Key::Left => LEFT, @@ -350,6 +355,7 @@ impl Key { Key::RAlt => RALT, Key::LGui => LGUI, Key::RGui => RGUI, + Key::Other(x) => x, } } } @@ -546,6 +552,15 @@ impl ColorU8 { pub fn as_tuple(self) -> (u8, u8, u8, u8) { (self.r, self.g, self.b, self.a) } + + pub fn slice_from_bytes(bytes: &[u8]) -> &[ColorU8] { + // SAFETY: it is safe to transmute since ColorU8 is repr(C) + let (prefix, colors, suffix) = unsafe { bytes.align_to() }; + // these should never panic since align_of(ColorU8) == 1 + assert_eq!(prefix.len(), 0); + assert_eq!(suffix.len(), 0); + colors + } } impl From<u32> for ColorU8 { @@ -573,7 +588,7 @@ impl ColorF32 { pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self { ColorF32 { r, g, b, a } } - + pub const fn gray(value: f32) -> Self { Self::rgb(value, value, value) } @@ -603,7 +618,7 @@ unsafe impl Color for ColorGrayscaleF32 { pub struct Shader { id: GLuint, - /// shaders should not be sent across threads because of the drop function. + /// shaders should not be sent across threads _unused: NoSendSync, } @@ -690,7 +705,7 @@ impl Drop for Shader { pub struct Program { id: GLuint, - /// programs should not be sent across threads because of the drop function. + /// programs should not be sent across threads _unused: NoSendSync, } @@ -753,7 +768,7 @@ pub struct Buffer { id: GLuint, stride: u32, count: u32, - /// buffers should not be sent across threads because of the drop function. + /// buffers should not be sent across threads _unused: NoSendSync, } @@ -769,21 +784,27 @@ impl Buffer { } } - unsafe fn bind(&self) { - gl::BindBuffer(gl::ARRAY_BUFFER, self.id); + fn bind(&self) { + unsafe { gl::BindBuffer(gl::ARRAY_BUFFER, self.id) }; } - unsafe fn set_data<T>(&mut self, data: &[T]) { - gl::BindBuffer(gl::ARRAY_BUFFER, self.id); + pub fn set_data<T>(&mut self, data: &[T]) { + if mem::size_of::<T>() as u64 > i32::MAX as u64 { + panic!("Buffer data item too large"); + } + + unsafe { gl::BindBuffer(gl::ARRAY_BUFFER, self.id) }; self.count = data.len() as u32; self.stride = mem::size_of::<T>() as u32; - gl::BufferData( - gl::ARRAY_BUFFER, - (self.count * self.stride) as _, - data.as_ptr() as _, - gl::STATIC_DRAW, - ); + unsafe { + gl::BufferData( + gl::ARRAY_BUFFER, + (self.count * self.stride) as _, + data.as_ptr() as _, + gl::STATIC_DRAW, + ); + } } } @@ -797,7 +818,7 @@ pub struct VertexArray { buffer: Buffer, id: GLuint, program: GLuint, - /// vertex arrays should not be sent across threads because of the drop function. + /// vertex arrays should not be sent across threads _unused: NoSendSync, } @@ -815,38 +836,56 @@ impl VertexArray { } } - unsafe fn bind(&self) { - gl::BindVertexArray(self.id); + fn bind(&self) { + unsafe { gl::BindVertexArray(self.id) }; } - unsafe fn attribnf(&mut self, n: u8, name: &str, offset: usize) -> bool { + fn attribnf(&mut self, n: u8, name: &str, offset: usize) -> bool { let Ok(cstring) = CString::new(name) else { return false }; let cstr = cstring.as_ptr() as *const GLchar; - let loc = gl::GetAttribLocation(self.program, cstr); + let loc = unsafe { gl::GetAttribLocation(self.program, cstr) }; let Ok(loc) = loc.try_into() else { return false }; - if offset + usize::from(n) * size_of::<f32>() > self.buffer.stride as usize { + if offset.saturating_add(usize::from(n) * size_of::<f32>()) > self.buffer.stride as usize { // offset too large return false; } self.bind(); self.buffer.bind(); - gl::VertexAttribPointer( - loc, - n.into(), - gl::FLOAT, - 0, - self.buffer.stride as _, - offset as _, - ); - gl::EnableVertexAttribArray(loc); + unsafe { + gl::VertexAttribPointer( + loc, + n.into(), + gl::FLOAT, + 0, + self.buffer.stride as _, + offset as _, + ); + gl::EnableVertexAttribArray(loc); + } true } - unsafe fn draw(&self) { + pub fn buffer_mut(&mut self) -> &mut Buffer { + &mut self.buffer + } + + pub fn attrib2f(&mut self, name: &str, offset: usize) -> bool { + self.attribnf(2, name, offset) + } + + pub fn attrib3f(&mut self, name: &str, offset: usize) -> bool { + self.attribnf(3, name, offset) + } + + pub fn attrib4f(&mut self, name: &str, offset: usize) -> bool { + self.attribnf(4, name, offset) + } + + pub fn draw(&self) { self.bind(); - gl::DrawArrays(gl::TRIANGLES, 0, self.buffer.count as i32); + unsafe { gl::DrawArrays(gl::TRIANGLES, 0, self.buffer.count as i32) }; } } @@ -878,7 +917,7 @@ pub struct Texture { params: TextureParams, width: usize, height: usize, - /// textures should not be sent across threads because of the drop function. + /// textures should not be sent across threads _unused: NoSendSync, } @@ -895,11 +934,13 @@ impl Texture { } } - unsafe fn bind(&self) { - gl::BindTexture(gl::TEXTURE_2D, self.id); + fn bind(&self) { + unsafe { + gl::BindTexture(gl::TEXTURE_2D, self.id); + } } - unsafe fn set_data<T: Color>( + pub fn set_data<T: Color>( &mut self, data: Option<&[T]>, width: usize, @@ -927,27 +968,29 @@ impl Texture { let params = &self.params; self.bind(); - gl::TexImage2D( - gl::TEXTURE_2D, - 0, - T::GL_FORMAT as GLint, - width, - height, - 0, - T::GL_FORMAT, - T::GL_TYPE, - ptr.cast(), - ); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_MIN_FILTER, - params.min_filter.to_gl(), - ); - gl::TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_MAG_FILTER, - params.mag_filter.to_gl(), - ); + unsafe { + gl::TexImage2D( + gl::TEXTURE_2D, + 0, + T::GL_FORMAT as GLint, + width, + height, + 0, + T::GL_FORMAT, + T::GL_TYPE, + ptr.cast(), + ); + gl::TexParameteri( + gl::TEXTURE_2D, + gl::TEXTURE_MIN_FILTER, + params.min_filter.to_gl(), + ); + gl::TexParameteri( + gl::TEXTURE_2D, + gl::TEXTURE_MAG_FILTER, + params.mag_filter.to_gl(), + ); + } Ok(()) } @@ -1066,24 +1109,26 @@ impl Framebuffer { } } - unsafe fn bind(&self) { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.id); + fn bind(&self) { + unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, self.id) }; } - unsafe fn unbind() { - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + fn unbind() { + unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, 0) }; } - unsafe fn set_texture(&mut self, attachment: FramebufferAttachment, texture: &Texture) { + pub fn set_texture(&mut self, attachment: FramebufferAttachment, texture: &Texture) { self.bind(); texture.bind(); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - attachment.to_gl(), - gl::TEXTURE_2D, - texture.id, - 0, - ); + unsafe { + gl::FramebufferTexture2D( + gl::FRAMEBUFFER, + attachment.to_gl(), + gl::TEXTURE_2D, + texture.id, + 0, + ); + } Self::unbind(); } } @@ -1194,7 +1239,7 @@ impl Window { ); } } - + pub fn set_icon(&mut self, bmp_filename: &str) { unsafe { if let Ok(icon) = sdl::load_bmp(bmp_filename) { @@ -1243,56 +1288,18 @@ impl Window { unsafe { Buffer::new() } } - pub fn set_buffer_data<T>(&mut self, buffer: &mut Buffer, data: &[T]) { - unsafe { buffer.set_data(data) }; - } - pub fn create_vertex_array(&mut self, buffer: Buffer, program: &Program) -> VertexArray { unsafe { VertexArray::new(buffer, program) } } - fn array_attribnf( - &mut self, - array: &mut VertexArray, - n: u8, - name: &str, - offset: usize, - ) -> bool { - unsafe { array.attribnf(n, name, offset) } - } - - pub fn array_attrib2f(&mut self, array: &mut VertexArray, name: &str, offset: usize) -> bool { - self.array_attribnf(array, 2, name, offset) - } - - pub fn array_attrib3f(&mut self, array: &mut VertexArray, name: &str, offset: usize) -> bool { - self.array_attribnf(array, 3, name, offset) - } - - pub fn array_attrib4f(&mut self, array: &mut VertexArray, name: &str, offset: usize) -> bool { - self.array_attribnf(array, 4, name, offset) - } - pub fn create_framebuffer(&mut self) -> Framebuffer { unsafe { Framebuffer::new() } } - /// Attach texture to framebuffer. - /// In theory this should check that `framebuffer` does not outlive `texture`, - /// but that would be difficult to do in a nice way. - pub fn set_framebuffer_texture( - &mut self, - framebuffer: &mut Framebuffer, - attachment: FramebufferAttachment, - texture: &Texture, - ) { - unsafe { framebuffer.set_texture(attachment, texture) }; - } - pub fn bind_framebuffer(&mut self, framebuffer: Option<&Framebuffer>) { match framebuffer { - Some(f) => unsafe { f.bind() }, - None => unsafe { Framebuffer::unbind() }, + Some(f) => f.bind(), + None => Framebuffer::unbind(), } } @@ -1325,14 +1332,13 @@ impl Window { sdl::SDL_QUIT => return Some(Event::Quit), sdl::SDL_KEYDOWN | sdl::SDL_KEYUP => { let keysym = unsafe { sdl.key }.keysym; - let scancode = keysym.scancode; - if let Some(key) = Key::from_sdl(scancode) { - let modifier = KeyModifier::from_sdl(keysym.r#mod); - if r#type == sdl::SDL_KEYDOWN { - return Some(Event::KeyDown { key, modifier }); - } else { - return Some(Event::KeyUp { key, modifier }); - } + let keycode = keysym.sym; + let key = Key::from_sdl(keycode); + let modifier = KeyModifier::from_sdl(keysym.r#mod); + if r#type == sdl::SDL_KEYDOWN { + return Some(Event::KeyDown { key, modifier }); + } else { + return Some(Event::KeyUp { key, modifier }); } } sdl::SDL_MOUSEMOTION => { @@ -1360,31 +1366,6 @@ impl Window { unsafe { Texture::new(params) } } - pub fn set_texture_data<T: Color>( - &mut self, - texture: &mut Texture, - data: &[T], - width: usize, - height: usize, - ) -> Result<(), String> { - unsafe { texture.set_data(Some(data), width, height) }?; - Ok(()) - } - - /// sets texture width + height but not data. - /// - /// NOTE: you must still specify the color type! - /// for framebuffers, etc. - pub fn set_texture_no_data<T: Color>( - &mut self, - texture: &mut Texture, - width: usize, - height: usize, - ) -> Result<(), String> { - unsafe { texture.set_data::<T>(None, width, height) }?; - Ok(()) - } - /// get texture image /// /// panicks if `data.len() != texture.width() * texture.height()` @@ -1542,7 +1523,7 @@ impl Window { assert_eq!(xyzw.len(), 4); self.uniform4f(name, xyzw[0], xyzw[1], xyzw[2], xyzw[3]) } - + pub fn uniform4f_color(&mut self, name: &str, color: ColorF32) { self.uniform4f(name, color.r, color.g, color.b, color.a); } @@ -1567,13 +1548,11 @@ impl Window { self.uniform1i(name, slot as i32); } - pub fn draw_array(&mut self, array: &VertexArray) { - unsafe { array.draw() }; - } - pub fn is_key_down(&self, key: Key) -> bool { let kbd_state = unsafe { sdl::get_keyboard_state() }; - kbd_state[key.to_sdl() as usize] != 0 + let mut scancodes = unsafe { sdl::get_scancodes_from_key(key.to_sdl()) }; + + scancodes.any(|scn| kbd_state[scn as usize] != 0) } pub fn any_key_down(&self, keys: &[Key]) -> bool { |