summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-01-22 15:20:30 -0500
committerpommicket <pommicket@gmail.com>2023-01-22 15:20:50 -0500
commit12cb5d119330d518dc9992c962c4cd748e8ef616 (patch)
tree0f36d1fd929ffe408e5e22072945eedfb7d466a8 /src
parent41edf14f207592ff95a7fca502fa49f5c917f967 (diff)
configurable resolution
Diffstat (limited to 'src')
-rw-r--r--src/fshader_post.glsl6
-rw-r--r--src/main.rs153
-rw-r--r--src/sdf.rs42
-rw-r--r--src/sdl.rs273
-rw-r--r--src/vshader_main.glsl8
-rw-r--r--src/vshader_post.glsl7
-rw-r--r--src/vshader_test.glsl7
-rw-r--r--src/win.rs299
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);
}
diff --git a/src/sdf.rs b/src/sdf.rs
index be9c470..8c38337 100644
--- a/src/sdf.rs
+++ b/src/sdf.rs
@@ -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) => {
diff --git a/src/sdl.rs b/src/sdl.rs
index 9971e0a..5574373 100644
--- a/src/sdl.rs
+++ b/src/sdl.rs
@@ -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);
+}
diff --git a/src/win.rs b/src/win.rs
index 5783b1c..18f3757 100644
--- a/src/win.rs
+++ b/src/win.rs
@@ -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 {