Skip to content

Instantly share code, notes, and snippets.

@rexim
Created March 19, 2021 12:43
Show Gist options
  • Save rexim/b58b42351e7215b5db584aae5c482771 to your computer and use it in GitHub Desktop.
Save rexim/b58b42351e7215b5db584aae5c482771 to your computer and use it in GitHub Desktop.
use std::ffi::{c_void, CStr, CString};
use std::os::raw::c_char;
const SDL_INIT_VIDEO: u32 = 0x00000020;
const SDL_WINDOW_RESIZABLE: u32 = 0x00000020;
const SDL_RENDERER_ACCELERATED: u32 = 0x00000002;
const SDL_QUIT: u32 = 0x100;
type RawSdlWindow = c_void;
type RawSdlRenderer = c_void;
#[repr(C, packed)]
struct SdlEvent {
tipe: u32,
#[allow(dead_code)]
padding: [u8; 52],
}
#[link(name = "SDL2")]
extern "C" {
fn SDL_Init(flags: u32) -> i32;
fn SDL_GetError() -> *const c_char;
fn SDL_Quit();
fn SDL_CreateWindow(
title: *const c_char,
x: i32,
y: i32,
w: i32,
h: i32,
flags: u32,
) -> *mut RawSdlWindow;
fn SDL_CreateRenderer(window: *mut RawSdlWindow, index: i32, flags: u32)
-> *mut RawSdlRenderer;
fn SDL_SetRenderDrawColor(renderer: *mut RawSdlRenderer, r: u8, g: u8, b: u8, a: u8) -> i32;
fn SDL_RenderPresent(renderer: *mut RawSdlRenderer);
fn SDL_RenderClear(renderer: *mut RawSdlRenderer) -> i32;
fn SDL_PollEvent(event: *mut SdlEvent) -> i32;
fn SDL_Delay(ms: u32);
fn SDL_DestroyWindow(window: *mut RawSdlWindow);
fn SDL_DestroyRenderer(renderer: *mut RawSdlRenderer);
}
struct SdlWindow {
raw: *mut RawSdlWindow,
}
fn sdl_error_result<T>() -> Result<T, &'static str> {
unsafe {
Err(CStr::from_ptr(SDL_GetError()).to_str().expect(
"Expected SDL to do their job properly and return UTF-8 compatible error messages",
))
}
}
impl SdlWindow {
fn create_renderer(&mut self, index: i32, flags: u32) -> Result<SdlRenderer, &'static str> {
unsafe {
let raw_renderer = SDL_CreateRenderer(self.raw, index, flags);
if raw_renderer.is_null() {
sdl_error_result()
} else {
Ok(SdlRenderer { raw: raw_renderer })
}
}
}
}
impl Drop for SdlWindow {
fn drop(&mut self) {
unsafe {
SDL_DestroyWindow(self.raw);
}
}
}
struct SdlRenderer {
raw: *mut RawSdlRenderer,
}
impl SdlRenderer {
fn set_draw_color(&mut self, r: u8, g: u8, b: u8, a: u8) -> Result<(), &'static str> {
unsafe {
if SDL_SetRenderDrawColor(self.raw, r, g, b, a) < 0 {
sdl_error_result()
} else {
Ok(())
}
}
}
fn present(&mut self) {
unsafe { SDL_RenderPresent(self.raw) }
}
fn clear(&mut self) -> Result<(), &'static str> {
unsafe {
if SDL_RenderClear(self.raw) < 0 {
sdl_error_result()
} else {
Ok(())
}
}
}
}
impl Drop for SdlRenderer {
fn drop(&mut self) {
unsafe {
SDL_DestroyRenderer(self.raw);
}
}
}
struct Sdl {}
impl Sdl {
fn init(flags: u32) -> Result<Self, &'static str> {
unsafe {
if SDL_Init(flags) < 0 {
sdl_error_result()
} else {
Ok(Self {})
}
}
}
fn create_window(
&mut self,
title: &str,
x: i32,
y: i32,
w: i32,
h: i32,
flags: u32,
) -> Result<SdlWindow, &'static str> {
unsafe {
let raw_title = CString::new(title).expect("Expect the unexpectable ZULUL");
let raw_window = SDL_CreateWindow(raw_title.as_ptr(), x, y, w, h, flags);
if raw_window.is_null() {
sdl_error_result()
} else {
Ok(SdlWindow { raw: raw_window })
}
}
}
fn poll_event(&mut self, event: &mut SdlEvent) -> bool {
unsafe { SDL_PollEvent(event as *mut SdlEvent) > 0 }
}
fn delay(&mut self, ms: u32) {
unsafe {
SDL_Delay(ms);
}
}
}
impl Drop for Sdl {
fn drop(&mut self) {
unsafe { SDL_Quit() }
}
}
fn main() {
let mut sdl = Sdl::init(SDL_INIT_VIDEO).expect("Could not initialize SDL");
let mut window = sdl
.create_window("Hello from Rust", 0, 0, 800, 600, SDL_WINDOW_RESIZABLE)
.expect("Could not create SDL window");
let mut renderer = window
.create_renderer(-1, SDL_RENDERER_ACCELERATED)
.expect("Could not initialize SDL renderer");
let mut quit = false;
while !quit {
let mut event: SdlEvent = SdlEvent {
tipe: 0,
padding: [0; 52],
};
while sdl.poll_event(&mut event) {
if event.tipe == SDL_QUIT {
quit = true;
}
}
renderer.set_draw_color(0x3D, 0x3D, 0x3D, 255).unwrap();
renderer.clear().unwrap();
renderer.present();
sdl.delay(100);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment