Skip to content

Commit ecd03de

Browse files
authored
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
1 parent f0cdbb3 commit ecd03de

File tree

5 files changed

+444
-4
lines changed

5 files changed

+444
-4
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ name = "renderer-target"
135135
[[example]]
136136
name = "events"
137137

138+
[[example]]
139+
name = "render-geometry"
140+
138141
[[example]]
139142
name = "renderer-texture"
140143

changelog.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ when upgrading from a version of rust-sdl2 to another.
33

44
### Next
55

6+
[PR #1472](https://github.com/Rust-SDL2/rust-sdl2/pull/1472) Add `Canvas::render_geometry`, `Canvas::render_geometry_raw` and an example that uses them both. Both these bindings use `SDL_RenderGeometryRaw`.
7+
68
[PR #1473](https://github.com/Rust-SDL2/rust-sdl2/pull/1473) **BREAKING CHANGE** Fix UB in `ToColor` implementations and remove implementation for `isize`.
79

810
[PR #1414](https://github.com/Rust-SDL2/rust-sdl2/pull/1414) Use `TTF_GlyphIsProvided32` and `TTF_GlyphMetrics32` instead of the 16 bit ones.

examples/render-geometry.rs

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
extern crate sdl2;
2+
3+
use sdl2::event::Event;
4+
use sdl2::keyboard::Keycode;
5+
use sdl2::pixels::Color;
6+
use sdl2::rect::FPoint;
7+
use sdl2::render::{RenderGeometryTextureParams, Vertex, VertexIndices};
8+
use std::mem::offset_of;
9+
use std::thread;
10+
use std::time::Duration;
11+
12+
fn main() {
13+
let sdl_context = sdl2::init().unwrap();
14+
let video_subsystem = sdl_context.video().unwrap();
15+
16+
let window = video_subsystem
17+
.window("Rust SDL2 render_geometry custom struct example", 800, 600)
18+
.position_centered()
19+
.opengl()
20+
.build()
21+
.unwrap();
22+
23+
let mut canvas = window.into_canvas().build().unwrap();
24+
25+
let mut event_pump = sdl_context.event_pump().unwrap();
26+
let mut running = true;
27+
28+
while running {
29+
for event in event_pump.poll_iter() {
30+
match event {
31+
Event::Quit { .. }
32+
| Event::KeyDown {
33+
keycode: Some(Keycode::Escape),
34+
..
35+
} => {
36+
running = false;
37+
}
38+
_ => {}
39+
}
40+
}
41+
42+
// black background
43+
canvas.set_draw_color(Color::BLACK);
44+
canvas.clear();
45+
46+
// First, draw a triangle using `render_geometry`. The `tex_coord` fields are unused but
47+
// must be provided, `render_geometry` only supports `sdl2::render::Vertex`.
48+
let vertices = [
49+
Vertex {
50+
position: FPoint::new(100.0, 200.0),
51+
color: Color::RED,
52+
tex_coord: FPoint::new(0.0, 0.0),
53+
},
54+
Vertex {
55+
position: FPoint::new(200.0, 200.0),
56+
color: Color::GREEN,
57+
tex_coord: FPoint::new(0.0, 0.0),
58+
},
59+
Vertex {
60+
position: FPoint::new(150.0, 100.0),
61+
color: Color::BLUE,
62+
tex_coord: FPoint::new(0.0, 0.0),
63+
},
64+
];
65+
canvas
66+
.render_geometry(&vertices, None, VertexIndices::Sequential)
67+
.expect("render_geometry failed (probably unsupported, see error message)");
68+
69+
// `render_geometry_raw` supports any custom struct as long as it contains the needed data
70+
// (or other layout compatible of the needed data).
71+
// The struct does not need to be `repr(C)` or `Copy` for example.
72+
struct MyVertex {
73+
// For demonstration purposes color is `[u8; 4]` here. `[u8; 4]` is layout-compatible
74+
// with `sdl2::pixels::Color`
75+
color: [u8; 4],
76+
// The struct may contain data not needed by SDL.
77+
#[expect(dead_code)]
78+
foo: Vec<u8>,
79+
// When defining your own vertex struct, using `FPoint` for position and tex_coord
80+
// (and `Color` for color) is the easiest way. These are obviously layout-compatible
81+
// with `FPoint` and `Color`, respectively.
82+
pos: FPoint,
83+
}
84+
85+
// Define the vertices of a square
86+
let vertices = [
87+
MyVertex {
88+
color: [0, 0, 0, 0xff],
89+
foo: b"some".to_vec(),
90+
pos: FPoint::new(300.0, 100.0),
91+
},
92+
MyVertex {
93+
color: [0, 0xff, 0, 0xff],
94+
foo: b"unrelated".to_vec(),
95+
pos: FPoint::new(400.0, 100.0),
96+
},
97+
MyVertex {
98+
color: [0xff, 0, 0, 0xff],
99+
foo: b"data".to_vec(),
100+
pos: FPoint::new(300.0, 200.0),
101+
},
102+
MyVertex {
103+
color: [0xff, 0xff, 0, 0xff],
104+
foo: b"!".to_vec(),
105+
pos: FPoint::new(400.0, 200.0),
106+
},
107+
];
108+
109+
// A square is rendered as two triangles (see indices)
110+
// SAFETY: core::mem::offset_of makes sure the offsets are right and alignment is respected.
111+
unsafe {
112+
canvas.render_geometry_raw(
113+
&vertices,
114+
offset_of!(MyVertex, pos),
115+
&vertices,
116+
offset_of!(MyVertex, color),
117+
None::<RenderGeometryTextureParams<()>>,
118+
&[[0, 1, 2], [1, 2, 3]],
119+
)
120+
}
121+
.expect("render_geometry_raw failed (probably unsupported, see error message)");
122+
123+
// Parameters can be reused, here only the positions are swapped out for new ones.
124+
// SAFETY: core::mem::offset_of makes sure the offsets are right and alignment is respected.
125+
// The offset 0 is correct because the element type of positions is `[f32; 2]`.
126+
unsafe {
127+
canvas.render_geometry_raw(
128+
&[
129+
[500.0f32, 100.0],
130+
[600.0, 100.0],
131+
[500.0, 200.0],
132+
[600.0, 200.0],
133+
],
134+
0,
135+
&vertices,
136+
offset_of!(MyVertex, color),
137+
None::<RenderGeometryTextureParams<()>>,
138+
&[[0, 1, 2], [1, 2, 3]],
139+
)
140+
}
141+
.expect("render_geometry_raw failed (probably unsupported, see error message)");
142+
143+
canvas.present();
144+
thread::sleep(Duration::from_millis(16));
145+
}
146+
}

src/sdl2/pixels.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,14 @@ impl Palette {
4848
// Already validated, so don't check again
4949
let ncolors = colors.len() as ::libc::c_int;
5050

51-
let colors = colors.iter().map(|color| color.raw()).collect::<Vec<_>>();
52-
53-
let result = unsafe { sys::SDL_SetPaletteColors(pal.raw, colors.as_ptr(), 0, ncolors) };
51+
let result = unsafe {
52+
sys::SDL_SetPaletteColors(
53+
pal.raw,
54+
colors.as_ptr().cast::<sys::SDL_Color>(),
55+
0,
56+
ncolors,
57+
)
58+
};
5459

5560
if result < 0 {
5661
Err(get_error())
@@ -88,6 +93,7 @@ fn create_palette() {
8893
assert!(palette.len() == 255);
8994
}
9095

96+
#[repr(C)]
9197
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
9298
pub struct Color {
9399
pub r: u8,

0 commit comments

Comments
 (0)