summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-12-18 16:29:51 -0500
committerpommicket <pommicket@gmail.com>2022-12-18 16:29:51 -0500
commit3da685e5a4408ee35879250505b0924b2cf686e2 (patch)
tree3fdd63f7830d0b907923d68ea783c906e6177cca /src
parent73ee0bb21050b305dac5352e07c7cfe03947be66 (diff)
icon
Diffstat (limited to 'src')
-rw-r--r--src/main.rs6
-rw-r--r--src/sdl.rs167
-rw-r--r--src/win.rs10
3 files changed, 179 insertions, 4 deletions
diff --git a/src/main.rs b/src/main.rs
index b73e036..d0383f9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
/*
@TODO:
- publish git repo
+- replace *mut SDL_Window with Window
- exe & window icon
- options for:
- max framerate
@@ -271,6 +272,7 @@ impl State {
fn new(settings: Settings) -> Result<Self, String> {
let mut window = win::Window::new("AutoSDF", 1280, 720, &Default::default())
.map_err(|e| format!("Error creating window: {e}"))?;
+ window.set_icon("icon.bmp");
let mut programs = Programs::new(&mut window);
let config = sdf::SceneConfig {
sdf_length: settings.get_usize("sdf-length").unwrap_or(500),
@@ -477,7 +479,7 @@ impl State {
let mut dz = 0.0;
let mut dl = 0.0;
let mut dt = 0.0;
-
+
let window = &self.window;
use win::Key::*;
@@ -514,7 +516,7 @@ impl State {
let mut speed_multiplier = if window.is_shift_down() { 10.0 } else { 1.0 };
speed_multiplier *= if window.is_ctrl_down() { 0.1 } else { 1.0 };
speed_multiplier *= frame_dt;
-
+
if dt != 0.0 {
let dt = dt * speed_multiplier;
self.view.pause();
diff --git a/src/sdl.rs b/src/sdl.rs
index b354c59..6d41911 100644
--- a/src/sdl.rs
+++ b/src/sdl.rs
@@ -3,6 +3,7 @@
#![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;
@@ -13,7 +14,8 @@ pub type SDL_bool = c_int;
pub type SDL_EventType = u32;
#[repr(C)]
pub struct SDL_Window(u8);
-pub type SDL_SysWMmsg = c_void;
+#[repr(transparent)]
+pub struct SDL_SysWMmsg(c_void); // opaque type
pub type SDL_Keycode = u32;
pub type SDL_Scancode = i32;
pub type SDL_JoystickID = i32;
@@ -27,6 +29,10 @@ pub type SDL_AudioDeviceID = u32;
pub type SDL_WindowEventID = c_int;
pub type SDL_GLContext = *mut SDL_GLContextData;
pub type SDL_GLattr = c_int;
+#[repr(transparent)]
+pub struct SDL_BlitMap(c_void); // opaque type
+#[repr(transparent)]
+pub struct SDL_RWops(c_void); // for most purposes, you don't care about the internals of this struct
pub const SDL_WINDOWPOS_UNDEFINED: c_int = 0x1FFF0000;
pub const SDL_QUIT: SDL_EventType = 0x100;
@@ -646,6 +652,118 @@ pub struct SDL_AudioSpec {
pub userdata: *mut c_void,
}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct SDL_Color {
+ r: u8,
+ g: u8,
+ b: u8,
+ a: u8,
+}
+
+pub type SDL_Colour = SDL_Color;
+
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct SDL_Rect {
+ x: c_int,
+ y: c_int,
+ w: c_int,
+ h: c_int,
+}
+
+
+#[repr(C)]
+pub struct SDL_Palette {
+ ncolors: c_int,
+ colors: *mut SDL_Color,
+ version: u32,
+ refcount: c_int,
+}
+
+#[repr(C)]
+pub struct SDL_PixelFormat {
+ pub format: u32,
+ palette: *mut SDL_Palette,
+ pub BitsPerPixel: u8,
+ pub BytesPerPixel: u8,
+ pub padding: [u8; 2],
+ pub Rmask: u32,
+ pub Gmask: u32,
+ pub Bmask: u32,
+ pub Amask: u32,
+ pub Rloss: u8,
+ pub Gloss: u8,
+ pub Bloss: u8,
+ pub Aloss: u8,
+ pub Rshift: u8,
+ pub Gshift: u8,
+ pub Bshift: u8,
+ pub Ashift: u8,
+ pub refcount: c_int,
+ next: *mut SDL_PixelFormat,
+}
+
+impl SDL_PixelFormat {
+ fn palette(&self) -> &SDL_Palette {
+ // SAFETY: this should be a valid pointer as long as self is a valid SDL_PixelFormat
+ unsafe { &*self.palette }
+ }
+ fn next(&self) -> Option<&SDL_PixelFormat> {
+ if self.next.is_null() {
+ None
+ } else {
+ // SAFETY: this should be a valid pointer as long as self is a valid SDL_PixelFormat
+ Some(unsafe { &*self.next })
+ }
+ }
+}
+
+#[repr(C)]
+pub struct SDL_Surface {
+ flags: u32,
+ format: *mut SDL_PixelFormat,
+ w: c_int,
+ h: c_int,
+ pitch: c_int,
+ pub pixels: *mut c_void,
+ pub userdata: *mut c_void,
+ locked: c_int,
+ list_blitmap: *mut c_void,
+ clip_rect: SDL_Rect,
+ map: *mut SDL_BlitMap,
+ refcount: c_int,
+}
+
+impl SDL_Surface {
+ pub fn flags(&self) -> u32 {
+ self.flags
+ }
+ pub fn width(&self) -> i32 {
+ self.w.try_into().unwrap()
+ }
+ pub fn height(&self) -> i32 {
+ self.h.try_into().unwrap()
+ }
+ pub fn pitch(&self) -> i32 {
+ self.pitch.try_into().unwrap()
+ }
+ pub fn locked(&self) -> i32 {
+ self.locked.try_into().unwrap()
+ }
+ pub fn pixel_format(&self) -> &SDL_PixelFormat {
+ // SAFETY: this should be a valid pointer as long as self is a valid SDL_Surface
+ unsafe { &*self.format }
+ }
+ pub fn clip_rect(&self) -> SDL_Rect {
+ self.clip_rect
+ }
+ pub fn size(&self) -> (i32, i32) {
+ (self.width(), self.height())
+ }
+}
+
impl SDL_AudioSpec {
pub fn new(
callback: SDL_AudioCallback,
@@ -668,6 +786,34 @@ impl SDL_AudioSpec {
}
}
+pub struct Surface {
+ ptr: *mut SDL_Surface
+}
+
+impl Surface {
+ /// 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`.
+ /// Make sure you only create one `Surface` for any particular surface pointer.
+ /// When the `Surface` is dropped, the `SDL_Surface` pointer will be freed.
+ pub unsafe fn from_raw(ptr: *mut SDL_Surface) -> Option<Self> {
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Self { ptr })
+ }
+ }
+}
+
+impl Drop for Surface {
+ fn drop(&mut self) {
+ // SAFETY: this should only be constructed with a valid SDL surface pointer,
+ // and the pointer should never be freed by anything else.
+ unsafe { SDL_FreeSurface(self.ptr) };
+ }
+}
+
#[link(name = "SDL2", kind = "dylib")]
extern "C" {
fn SDL_Init(flags: u32) -> c_int;
@@ -694,6 +840,7 @@ extern "C" {
fn SDL_SetWindowSize(window: *mut SDL_Window, w: c_int, h: c_int);
fn SDL_SetRelativeMouseMode(enabled: SDL_bool) -> c_int;
fn SDL_GetError() -> *const c_char;
+ fn SDL_SetWindowIcon(window: *mut SDL_Window, icon: *mut SDL_Surface);
fn SDL_SetHint(name: *const c_char, value: *const c_char) -> SDL_bool;
fn SDL_GL_SetAttribute(attr: SDL_GLattr, value: c_int);
fn SDL_GL_SetSwapInterval(interval: c_int) -> c_int;
@@ -716,7 +863,11 @@ extern "C" {
fn SDL_GetClipboardText() -> *mut c_char;
fn SDL_SetClipboardText(text: *const c_char) -> c_int;
fn SDL_SetWindowFullscreen(window: *mut SDL_Window, flags: u32) -> c_int;
+ fn SDL_LoadBMP(file: *const c_char) -> *mut SDL_Surface;
fn SDL_free(mem: *mut c_void);
+ fn SDL_FreeSurface(surface: *mut SDL_Surface);
+ fn SDL_RWFromFile(file: *const c_char, mode: *const c_char) -> *mut SDL_RWops;
+ fn SDL_LoadBMP_RW(src: *mut SDL_RWops, freesrc: c_int) -> *mut SDL_Surface;
}
pub mod scancode {
@@ -1182,3 +1333,17 @@ pub unsafe fn set_window_fullscreen(win: *mut SDL_Window, flags: u32) -> Result<
Err(get_err())
}
}
+
+pub unsafe fn load_bmp(filename: &str) -> Result<Surface, String> {
+ let Ok(cstring) = CString::new(filename) else {
+ return Err("filename contains null bytes.".to_string());
+ };
+ // note: this is how SDL_LoadBMP is #defined in SDL_surface.h
+ let rwops = SDL_RWFromFile(cstring.as_ptr(), b"rb\0".as_ptr().cast());
+ let raw = SDL_LoadBMP_RW(rwops, 1);
+ Surface::from_raw(raw).ok_or_else(|| get_err())
+}
+
+pub unsafe fn set_window_icon(win: *mut SDL_Window, icon: &Surface) {
+ SDL_SetWindowIcon(win, icon.ptr);
+}
diff --git a/src/win.rs b/src/win.rs
index 5a30dc5..8f031f0 100644
--- a/src/win.rs
+++ b/src/win.rs
@@ -579,7 +579,7 @@ unsafe impl Color for ColorF32 {
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct ColorGrayscaleF32 {
- pub value: f32
+ pub value: f32,
}
impl ColorGrayscaleF32 {
@@ -1186,6 +1186,14 @@ impl Window {
);
}
}
+
+ pub fn set_icon(&mut self, bmp_filename: &str) {
+ unsafe {
+ if let Ok(icon) = sdl::load_bmp(bmp_filename) {
+ sdl::set_window_icon(self.sdlwin, &icon);
+ }
+ }
+ }
pub fn show(&mut self) {
unsafe { sdl::show_window(self.sdlwin) };