Skip to content

Commit c2e0894

Browse files
committed
add binding for SDL_ComposeCustomBlendMode
closes Rust-SDL2#878 closes Rust-SDL2#1439
1 parent ebde010 commit c2e0894

File tree

4 files changed

+231
-52
lines changed

4 files changed

+231
-52
lines changed

sdl2-sys/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ fn generate_bindings(target: &str, host: &str, headers_paths: &[String]) {
660660
.allowlist_item("(SDL|AUDIO|RW)_.*")
661661
.bitfield_enum("SDL_RendererFlip")
662662
.newtype_enum("SDL_Keymod")
663+
.newtype_enum("SDL_BlendMode")
663664
.default_enum_style(bindgen::EnumVariation::Rust {
664665
non_exhaustive: false,
665666
})

sdl2-sys/sdl_bindings.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,22 +2495,23 @@ unsafe extern "C" {
24952495
Y2: *mut f32,
24962496
) -> SDL_bool;
24972497
}
2498-
#[repr(u32)]
2499-
#[doc = " The blend mode used in SDL_RenderCopy() and drawing operations."]
2500-
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
2501-
pub enum SDL_BlendMode {
2498+
impl SDL_BlendMode {
25022499
#[doc = "< no blending\ndstRGBA = srcRGBA"]
2503-
SDL_BLENDMODE_NONE = 0,
2500+
pub const SDL_BLENDMODE_NONE: SDL_BlendMode = SDL_BlendMode(0);
25042501
#[doc = "< alpha blending\ndstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))\ndstA = srcA + (dstA * (1-srcA))"]
2505-
SDL_BLENDMODE_BLEND = 1,
2502+
pub const SDL_BLENDMODE_BLEND: SDL_BlendMode = SDL_BlendMode(1);
25062503
#[doc = "< additive blending\ndstRGB = (srcRGB * srcA) + dstRGB\ndstA = dstA"]
2507-
SDL_BLENDMODE_ADD = 2,
2504+
pub const SDL_BLENDMODE_ADD: SDL_BlendMode = SDL_BlendMode(2);
25082505
#[doc = "< color modulate\ndstRGB = srcRGB * dstRGB\ndstA = dstA"]
2509-
SDL_BLENDMODE_MOD = 4,
2506+
pub const SDL_BLENDMODE_MOD: SDL_BlendMode = SDL_BlendMode(4);
25102507
#[doc = "< color multiply\ndstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))\ndstA = dstA"]
2511-
SDL_BLENDMODE_MUL = 8,
2512-
SDL_BLENDMODE_INVALID = 2147483647,
2508+
pub const SDL_BLENDMODE_MUL: SDL_BlendMode = SDL_BlendMode(8);
2509+
pub const SDL_BLENDMODE_INVALID: SDL_BlendMode = SDL_BlendMode(2147483647);
25132510
}
2511+
#[repr(transparent)]
2512+
#[doc = " The blend mode used in SDL_RenderCopy() and drawing operations."]
2513+
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
2514+
pub struct SDL_BlendMode(pub libc::c_uint);
25142515
#[repr(u32)]
25152516
#[doc = " The blend operation used when combining source and destination pixel\n components"]
25162517
#[derive(Copy, Clone, Hash, PartialEq, Eq)]

src/sdl2/render.rs

Lines changed: 214 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! 2D accelerated rendering
22
//!
3-
//! Official C documentation: https://wiki.libsdl.org/CategoryRender
3+
//! Official C documentation: <https://wiki.libsdl.org/SDL2/CategoryRender>
44
//! # Introduction
55
//!
66
//! This module contains functions for 2D accelerated rendering.
@@ -55,9 +55,9 @@ use std::rc::Rc;
5555
use std::slice;
5656

5757
use crate::sys;
58-
use crate::sys::SDL_BlendMode;
59-
use crate::sys::SDL_ScaleMode;
60-
use crate::sys::SDL_TextureAccess;
58+
use crate::sys::{
59+
SDL_BlendFactor, SDL_BlendMode, SDL_BlendOperation, SDL_ScaleMode, SDL_TextureAccess,
60+
};
6161

6262
/// Contains the description of an error returned by SDL
6363
#[derive(Debug, Clone)]
@@ -133,52 +133,234 @@ pub struct RendererInfo {
133133
}
134134

135135
/// Blend mode for `Canvas`, `Texture` or `Surface`.
136-
#[repr(i32)]
137-
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
138-
pub enum BlendMode {
139-
/// no blending (replace destination with source).
140-
None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
136+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
137+
pub struct BlendMode(pub SDL_BlendMode);
138+
139+
impl fmt::Debug for BlendMode {
140+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141+
f.debug_tuple("BlendMode").field(&self.0 .0).finish()
142+
}
143+
}
144+
145+
#[expect(non_upper_case_globals, reason = "deprecated constants")]
146+
impl BlendMode {
147+
/// No blending (replace destination with source).
148+
pub const NONE: Self = Self(SDL_BlendMode::SDL_BLENDMODE_NONE);
149+
#[deprecated(
150+
since = "0.39.0",
151+
note = "use NONE instead, this used to be an enum member"
152+
)]
153+
pub const None: Self = Self::NONE;
154+
141155
/// Alpha blending
142156
///
143157
/// dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
144158
///
145159
/// dstA = srcA + (dstA * (1-srcA))
146-
Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
160+
pub const BLEND: Self = Self(SDL_BlendMode::SDL_BLENDMODE_BLEND);
161+
#[deprecated(
162+
since = "0.39.0",
163+
note = "use BLEND instead, this used to be an enum member"
164+
)]
165+
pub const Blend: Self = Self::BLEND;
166+
147167
/// Additive blending
148168
///
149169
/// dstRGB = (srcRGB * srcA) + dstRGB
150170
///
151171
/// dstA = dstA (keep original alpha)
152-
Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
172+
pub const ADD: Self = Self(SDL_BlendMode::SDL_BLENDMODE_ADD);
173+
#[deprecated(
174+
since = "0.39.0",
175+
note = "use ADD instead, this used to be an enum member"
176+
)]
177+
pub const Add: Self = Self::ADD;
178+
153179
/// Color modulate
154180
///
155181
/// dstRGB = srcRGB * dstRGB
156-
Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
182+
pub const MOD: Self = Self(SDL_BlendMode::SDL_BLENDMODE_MOD);
183+
#[deprecated(
184+
since = "0.39.0",
185+
note = "use MOD instead, this used to be an enum member"
186+
)]
187+
pub const Mod: Self = Self::MOD;
188+
157189
/// Color multiply
158-
Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
190+
pub const MUL: Self = Self(SDL_BlendMode::SDL_BLENDMODE_MUL);
191+
#[deprecated(
192+
since = "0.39.0",
193+
note = "use MUL instead, this used to be an enum member"
194+
)]
195+
pub const Mul: Self = Self::MUL;
196+
159197
/// Invalid blending mode (indicates error)
160-
Invalid = SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
161-
}
198+
pub const INVALID: Self = Self(SDL_BlendMode::SDL_BLENDMODE_INVALID);
199+
#[deprecated(
200+
since = "0.39.0",
201+
note = "use INVALID instead, this used to be an enum member"
202+
)]
203+
pub const Invalid: Self = Self::INVALID;
204+
}
205+
206+
macro_rules! enum_binding {
207+
(
208+
$(#[$meta:meta])*
209+
pub enum $enum:ident = $sdl_enum:ident {$(
210+
#[$($member_meta:meta)*]
211+
$member:ident = $sdl_constant:ident,
212+
)*}
213+
) => {
214+
$(#[$meta])*
215+
///
216+
#[doc = concat!("SDL C API type: [`", stringify!($sdl_enum), "`].")]
217+
/// [`From`] implementations are provided to convert between this type and the C API type.
218+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
219+
pub enum $enum {$(
220+
$member = $sdl_enum::$sdl_constant as isize,
221+
)*}
222+
223+
impl From<$sdl_enum> for $enum {
224+
fn from(value: $sdl_enum) -> Self {
225+
match value {$(
226+
$sdl_enum::$sdl_constant => Self::$member,
227+
)*}
228+
}
229+
}
162230

163-
impl TryFrom<u32> for BlendMode {
164-
type Error = ();
231+
impl From<$enum> for $sdl_enum {
232+
fn from(value: $enum) -> Self {
233+
match value {$(
234+
$enum::$member => Self::$sdl_constant,
235+
)*}
236+
}
237+
}
238+
};
239+
}
165240

166-
fn try_from(n: u32) -> Result<Self, Self::Error> {
167-
use self::BlendMode::*;
168-
use crate::sys::SDL_BlendMode::*;
241+
enum_binding! {
242+
/// The blend operation used when combining source and destination pixel components.
243+
pub enum BlendOperation = SDL_BlendOperation {
244+
/// dst + src: supported by all renderers
245+
Add = SDL_BLENDOPERATION_ADD,
246+
/// dst - src: supported by D3D9, D3D11, OpenGL, OpenGLES
247+
Subtract = SDL_BLENDOPERATION_SUBTRACT,
248+
/// src - dst: supported by D3D9, D3D11, OpenGL, OpenGLES
249+
RevSubtract = SDL_BLENDOPERATION_REV_SUBTRACT,
250+
/// min(dst, src): supported by D3D9, D3D11
251+
Minimum = SDL_BLENDOPERATION_MINIMUM,
252+
/// max(dst, src): supported by D3D9, D3D11
253+
Maximum = SDL_BLENDOPERATION_MAXIMUM,
254+
}
255+
}
256+
257+
enum_binding! {
258+
/// The normalized factor used to multiply pixel components.
259+
pub enum BlendFactor = SDL_BlendFactor {
260+
/// 0, 0, 0, 0
261+
Zero = SDL_BLENDFACTOR_ZERO,
262+
/// 1, 1, 1, 1
263+
One = SDL_BLENDFACTOR_ONE,
264+
/// srcR, srcG, srcB, srcA
265+
SrcColor = SDL_BLENDFACTOR_SRC_COLOR,
266+
/// 1-srcR, 1-srcG, 1-srcB, 1-srcA
267+
OneMinusSrcColor = SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR,
268+
/// srcA, srcA, srcA, srcA
269+
SrcAlpha = SDL_BLENDFACTOR_SRC_ALPHA,
270+
/// 1-srcA, 1-srcA, 1-srcA, 1-srcA
271+
OneMinusSrcAlpha = SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
272+
/// dstR, dstG, dstB, dstA
273+
DstColor = SDL_BLENDFACTOR_DST_COLOR,
274+
/// 1-dstR, 1-dstG, 1-dstB, 1-dstA
275+
OneMinusDstColor = SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR,
276+
/// dstA, dstA, dstA, dstA
277+
DstAlpha = SDL_BLENDFACTOR_DST_ALPHA,
278+
/// 1-dstA, 1-dstA, 1-dstA, 1-dstA
279+
OneMinusDstAlpha = SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA,
280+
}
281+
}
282+
283+
/// Arguments to [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
284+
///
285+
/// This struct implements [`Default`] with a blend mode equivalent to [`BlendMode::NONE`].
286+
/// Struct update syntax ([Rust Book][book-struct-update], [Rust Reference][reference-struct-update]) can be used to only change a few arguments.
287+
///
288+
/// See [`Self::compose`] for examples.
289+
///
290+
/// [book-struct-update]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
291+
/// [reference-struct-update]: https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax
292+
#[derive(Debug, Clone, Copy)]
293+
pub struct CustomBlendMode {
294+
pub src_color_factor: BlendFactor,
295+
pub dst_color_factor: BlendFactor,
296+
pub color_operation: BlendOperation,
297+
pub src_alpha_factor: BlendFactor,
298+
pub dst_alpha_factor: BlendFactor,
299+
pub alpha_operation: BlendOperation,
300+
}
169301

170-
match n {
171-
x if x == SDL_BLENDMODE_NONE as u32 => Ok(None),
172-
x if x == SDL_BLENDMODE_BLEND as u32 => Ok(Blend),
173-
x if x == SDL_BLENDMODE_ADD as u32 => Ok(Add),
174-
x if x == SDL_BLENDMODE_MOD as u32 => Ok(Mod),
175-
x if x == SDL_BLENDMODE_MUL as u32 => Ok(Mul),
176-
x if x == SDL_BLENDMODE_INVALID as u32 => Ok(Invalid),
177-
_ => Err(()),
302+
impl Default for CustomBlendMode {
303+
fn default() -> Self {
304+
Self {
305+
src_color_factor: BlendFactor::One,
306+
dst_color_factor: BlendFactor::Zero,
307+
color_operation: BlendOperation::Add,
308+
src_alpha_factor: BlendFactor::One,
309+
dst_alpha_factor: BlendFactor::Zero,
310+
alpha_operation: BlendOperation::Add,
178311
}
179312
}
180313
}
181314

315+
impl CustomBlendMode {
316+
/// Compose a custom blend mode for renderers.
317+
///
318+
/// # Examples
319+
///
320+
/// ```
321+
/// use sdl2::render::{BlendFactor, BlendOperation, CustomBlendMode};
322+
///
323+
/// let no_blending = CustomBlendMode {
324+
/// src_color_factor: BlendFactor::One,
325+
/// dst_color_factor: BlendFactor::Zero,
326+
/// color_operation: BlendOperation::Add,
327+
/// src_alpha_factor: BlendFactor::One,
328+
/// dst_alpha_factor: BlendFactor::Zero,
329+
/// alpha_operation: BlendOperation::Add,
330+
/// }.compose();
331+
///
332+
/// let ignore_alpha = CustomBlendMode {
333+
/// src_alpha_factor: BlendFactor::Zero,
334+
/// dst_alpha_factor: BlendFactor::One,
335+
/// ..Default::default()
336+
/// }.compose();
337+
/// ```
338+
///
339+
/// See [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
340+
#[doc(alias = "SDL_ComposeCustomBlendMode")]
341+
pub fn compose(self) -> BlendMode {
342+
let Self {
343+
src_color_factor,
344+
dst_color_factor,
345+
color_operation,
346+
src_alpha_factor,
347+
dst_alpha_factor,
348+
alpha_operation,
349+
} = self;
350+
351+
BlendMode(unsafe {
352+
sys::SDL_ComposeCustomBlendMode(
353+
src_color_factor.into(),
354+
dst_color_factor.into(),
355+
color_operation.into(),
356+
src_alpha_factor.into(),
357+
dst_alpha_factor.into(),
358+
alpha_operation.into(),
359+
)
360+
})
361+
}
362+
}
363+
182364
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
183365
pub enum ScaleMode {
184366
/// nearest pixel sampling. default
@@ -1100,8 +1282,7 @@ impl<T: RenderTarget> Canvas<T> {
11001282
/// Sets the blend mode used for drawing operations (Fill and Line).
11011283
#[doc(alias = "SDL_SetRenderDrawBlendMode")]
11021284
pub fn set_blend_mode(&mut self, blend: BlendMode) {
1103-
let ret =
1104-
unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32)) };
1285+
let ret = unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, blend.0) };
11051286
// Should only fail on an invalid renderer
11061287
if ret != 0 {
11071288
panic!("{}", get_error())
@@ -1117,8 +1298,7 @@ impl<T: RenderTarget> Canvas<T> {
11171298
if ret != 0 {
11181299
panic!("{}", get_error())
11191300
} else {
1120-
let blend = unsafe { blend.assume_init() };
1121-
BlendMode::try_from(blend as u32).unwrap()
1301+
BlendMode(unsafe { blend.assume_init() })
11221302
}
11231303
}
11241304

@@ -2543,7 +2723,7 @@ impl InternalTexture {
25432723

25442724
#[doc(alias = "SDL_SetTextureBlendMode")]
25452725
pub fn set_blend_mode(&mut self, blend: BlendMode) {
2546-
let ret = unsafe { sys::SDL_SetTextureBlendMode(self.raw, transmute(blend as u32)) };
2726+
let ret = unsafe { sys::SDL_SetTextureBlendMode(self.raw, blend.0) };
25472727

25482728
if ret != 0 {
25492729
panic!("Error setting blend: {}", get_error())
@@ -2559,8 +2739,7 @@ impl InternalTexture {
25592739
if ret != 0 {
25602740
panic!("{}", get_error())
25612741
} else {
2562-
let blend = unsafe { blend.assume_init() };
2563-
BlendMode::try_from(blend as u32).unwrap()
2742+
BlendMode(unsafe { blend.assume_init() })
25642743
}
25652744
}
25662745

src/sdl2/surface.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ use crate::render::{BlendMode, Canvas};
1111
use crate::render::{Texture, TextureCreator, TextureValueError};
1212
use crate::rwops::RWops;
1313
use libc::c_int;
14-
use std::convert::TryFrom;
15-
use std::mem::transmute;
1614
use std::ptr;
1715

1816
use crate::sys;
@@ -595,8 +593,8 @@ impl SurfaceRef {
595593

596594
/// The function will fail if the blend mode is not supported by SDL.
597595
#[doc(alias = "SDL_SetSurfaceBlendMode")]
598-
pub fn set_blend_mode(&mut self, mode: BlendMode) -> Result<(), String> {
599-
let result = unsafe { sys::SDL_SetSurfaceBlendMode(self.raw(), transmute(mode)) };
596+
pub fn set_blend_mode(&mut self, blend: BlendMode) -> Result<(), String> {
597+
let result = unsafe { sys::SDL_SetSurfaceBlendMode(self.raw(), blend.0) };
600598

601599
match result {
602600
0 => Ok(()),
@@ -606,11 +604,11 @@ impl SurfaceRef {
606604

607605
#[doc(alias = "SDL_GetSurfaceBlendMode")]
608606
pub fn blend_mode(&self) -> BlendMode {
609-
let mut mode = sys::SDL_BlendMode::SDL_BLENDMODE_NONE;
610-
let result = unsafe { sys::SDL_GetSurfaceBlendMode(self.raw(), &mut mode) };
607+
let mut blend: mem::MaybeUninit<sys::SDL_BlendMode> = mem::MaybeUninit::uninit();
608+
let result = unsafe { sys::SDL_GetSurfaceBlendMode(self.raw(), blend.as_mut_ptr()) };
611609

612610
match result {
613-
0 => BlendMode::try_from(mode as u32).unwrap(),
611+
0 => BlendMode(unsafe { blend.assume_init() }),
614612
// Should only fail on a null Surface
615613
_ => panic!("{}", get_error()),
616614
}

0 commit comments

Comments
 (0)