Files
archived-rust-sdl2/examples/render-geometry.rs
Antoni Spaanderman ecd03de215 Render geometry binding (#1472)
* 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
2025-03-31 09:20:58 +02:00

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));
}
}