mirror of
https://github.com/touchHLE/rust-sdl2.git
synced 2026-01-31 01:25:23 +01:00
* make `pixels::Color` have a stable representation (`repr(C)`) this allows for faster code and is also needed for SDL_RenderGeometry * add binding for SDL_RenderGeometryRaw * add example of advanced use of `Canvas::render_geometry` * update unsafe trait docs to include a needed guarantee and refer to one doc comment instead of duplicating similar ones * rework almost everything - the macro was very hard to get sound, auto deref has to be prevented somehow - the unsafe traits could not be implemented for types defined in other crates the unsafety must be kept simple, users now only need to provide the right offsets, which core::mem::offset_of does update example * add convenience impls for &Vec<_> to VertexIndices * update example to use 2 ways of using render_geometry_raw, and use render_geometry * mention alignment in safety comments in render_geometry example * fix and improve docs * update changelog
147 lines
5.1 KiB
Rust
147 lines
5.1 KiB
Rust
extern crate sdl2;
|
|
|
|
use sdl2::event::Event;
|
|
use sdl2::keyboard::Keycode;
|
|
use sdl2::pixels::Color;
|
|
use sdl2::rect::FPoint;
|
|
use sdl2::render::{RenderGeometryTextureParams, Vertex, VertexIndices};
|
|
use std::mem::offset_of;
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
fn main() {
|
|
let sdl_context = sdl2::init().unwrap();
|
|
let video_subsystem = sdl_context.video().unwrap();
|
|
|
|
let window = video_subsystem
|
|
.window("Rust SDL2 render_geometry custom struct example", 800, 600)
|
|
.position_centered()
|
|
.opengl()
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut canvas = window.into_canvas().build().unwrap();
|
|
|
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
|
let mut running = true;
|
|
|
|
while running {
|
|
for event in event_pump.poll_iter() {
|
|
match event {
|
|
Event::Quit { .. }
|
|
| Event::KeyDown {
|
|
keycode: Some(Keycode::Escape),
|
|
..
|
|
} => {
|
|
running = false;
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
// black background
|
|
canvas.set_draw_color(Color::BLACK);
|
|
canvas.clear();
|
|
|
|
// First, draw a triangle using `render_geometry`. The `tex_coord` fields are unused but
|
|
// must be provided, `render_geometry` only supports `sdl2::render::Vertex`.
|
|
let vertices = [
|
|
Vertex {
|
|
position: FPoint::new(100.0, 200.0),
|
|
color: Color::RED,
|
|
tex_coord: FPoint::new(0.0, 0.0),
|
|
},
|
|
Vertex {
|
|
position: FPoint::new(200.0, 200.0),
|
|
color: Color::GREEN,
|
|
tex_coord: FPoint::new(0.0, 0.0),
|
|
},
|
|
Vertex {
|
|
position: FPoint::new(150.0, 100.0),
|
|
color: Color::BLUE,
|
|
tex_coord: FPoint::new(0.0, 0.0),
|
|
},
|
|
];
|
|
canvas
|
|
.render_geometry(&vertices, None, VertexIndices::Sequential)
|
|
.expect("render_geometry failed (probably unsupported, see error message)");
|
|
|
|
// `render_geometry_raw` supports any custom struct as long as it contains the needed data
|
|
// (or other layout compatible of the needed data).
|
|
// The struct does not need to be `repr(C)` or `Copy` for example.
|
|
struct MyVertex {
|
|
// For demonstration purposes color is `[u8; 4]` here. `[u8; 4]` is layout-compatible
|
|
// with `sdl2::pixels::Color`
|
|
color: [u8; 4],
|
|
// The struct may contain data not needed by SDL.
|
|
#[expect(dead_code)]
|
|
foo: Vec<u8>,
|
|
// When defining your own vertex struct, using `FPoint` for position and tex_coord
|
|
// (and `Color` for color) is the easiest way. These are obviously layout-compatible
|
|
// with `FPoint` and `Color`, respectively.
|
|
pos: FPoint,
|
|
}
|
|
|
|
// Define the vertices of a square
|
|
let vertices = [
|
|
MyVertex {
|
|
color: [0, 0, 0, 0xff],
|
|
foo: b"some".to_vec(),
|
|
pos: FPoint::new(300.0, 100.0),
|
|
},
|
|
MyVertex {
|
|
color: [0, 0xff, 0, 0xff],
|
|
foo: b"unrelated".to_vec(),
|
|
pos: FPoint::new(400.0, 100.0),
|
|
},
|
|
MyVertex {
|
|
color: [0xff, 0, 0, 0xff],
|
|
foo: b"data".to_vec(),
|
|
pos: FPoint::new(300.0, 200.0),
|
|
},
|
|
MyVertex {
|
|
color: [0xff, 0xff, 0, 0xff],
|
|
foo: b"!".to_vec(),
|
|
pos: FPoint::new(400.0, 200.0),
|
|
},
|
|
];
|
|
|
|
// A square is rendered as two triangles (see indices)
|
|
// SAFETY: core::mem::offset_of makes sure the offsets are right and alignment is respected.
|
|
unsafe {
|
|
canvas.render_geometry_raw(
|
|
&vertices,
|
|
offset_of!(MyVertex, pos),
|
|
&vertices,
|
|
offset_of!(MyVertex, color),
|
|
None::<RenderGeometryTextureParams<()>>,
|
|
&[[0, 1, 2], [1, 2, 3]],
|
|
)
|
|
}
|
|
.expect("render_geometry_raw failed (probably unsupported, see error message)");
|
|
|
|
// Parameters can be reused, here only the positions are swapped out for new ones.
|
|
// SAFETY: core::mem::offset_of makes sure the offsets are right and alignment is respected.
|
|
// The offset 0 is correct because the element type of positions is `[f32; 2]`.
|
|
unsafe {
|
|
canvas.render_geometry_raw(
|
|
&[
|
|
[500.0f32, 100.0],
|
|
[600.0, 100.0],
|
|
[500.0, 200.0],
|
|
[600.0, 200.0],
|
|
],
|
|
0,
|
|
&vertices,
|
|
offset_of!(MyVertex, color),
|
|
None::<RenderGeometryTextureParams<()>>,
|
|
&[[0, 1, 2], [1, 2, 3]],
|
|
)
|
|
}
|
|
.expect("render_geometry_raw failed (probably unsupported, see error message)");
|
|
|
|
canvas.present();
|
|
thread::sleep(Duration::from_millis(16));
|
|
}
|
|
}
|