Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ when upgrading from a version of rust-sdl2 to another.

### v0.39.0

[PR #1507](https://github.com/Rust-SDL2/rust-sdl2/pull/1507) **BREAKING CHANGE** Add binding for `SDL_ComposeCustomBlendMode`. This should only be a breaking change for users relying on internal details of `BlendMode` and `SDL_BlendMode`.

[PR #1510](https://github.com/Rust-SDL2/rust-sdl2/pull/1510) Fix clippy warnings.

[PR #1509](https://github.com/Rust-SDL2/rust-sdl2/pull/1509) **BREAKING CHANGE** Add Send + 'static bounds for EventWatchCallback and 'static bound to AudioCallback to avoid soundness hole.
Expand Down
1 change: 1 addition & 0 deletions sdl2-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ fn generate_bindings(target: &str, host: &str, headers_paths: &[String]) {
.allowlist_item("(SDL|AUDIO|RW)_.*")
.bitfield_enum("SDL_RendererFlip")
.newtype_enum("SDL_Keymod")
.newtype_enum("SDL_BlendMode")
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
Expand Down
21 changes: 11 additions & 10 deletions sdl2-sys/sdl_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2495,22 +2495,23 @@ unsafe extern "C" {
Y2: *mut f32,
) -> SDL_bool;
}
#[repr(u32)]
#[doc = " The blend mode used in SDL_RenderCopy() and drawing operations."]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum SDL_BlendMode {
impl SDL_BlendMode {
#[doc = "< no blending\ndstRGBA = srcRGBA"]
SDL_BLENDMODE_NONE = 0,
pub const SDL_BLENDMODE_NONE: SDL_BlendMode = SDL_BlendMode(0);
#[doc = "< alpha blending\ndstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))\ndstA = srcA + (dstA * (1-srcA))"]
SDL_BLENDMODE_BLEND = 1,
pub const SDL_BLENDMODE_BLEND: SDL_BlendMode = SDL_BlendMode(1);
#[doc = "< additive blending\ndstRGB = (srcRGB * srcA) + dstRGB\ndstA = dstA"]
SDL_BLENDMODE_ADD = 2,
pub const SDL_BLENDMODE_ADD: SDL_BlendMode = SDL_BlendMode(2);
#[doc = "< color modulate\ndstRGB = srcRGB * dstRGB\ndstA = dstA"]
SDL_BLENDMODE_MOD = 4,
pub const SDL_BLENDMODE_MOD: SDL_BlendMode = SDL_BlendMode(4);
#[doc = "< color multiply\ndstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))\ndstA = dstA"]
SDL_BLENDMODE_MUL = 8,
SDL_BLENDMODE_INVALID = 2147483647,
pub const SDL_BLENDMODE_MUL: SDL_BlendMode = SDL_BlendMode(8);
pub const SDL_BLENDMODE_INVALID: SDL_BlendMode = SDL_BlendMode(2147483647);
}
#[repr(transparent)]
#[doc = " The blend mode used in SDL_RenderCopy() and drawing operations."]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct SDL_BlendMode(pub libc::c_uint);
#[repr(u32)]
#[doc = " The blend operation used when combining source and destination pixel\n components"]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
Expand Down
249 changes: 214 additions & 35 deletions src/sdl2/render.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! 2D accelerated rendering
//!
//! Official C documentation: https://wiki.libsdl.org/CategoryRender
//! Official C documentation: <https://wiki.libsdl.org/SDL2/CategoryRender>
//! # Introduction
//!
//! This module contains functions for 2D accelerated rendering.
Expand Down Expand Up @@ -55,9 +55,9 @@ use std::rc::Rc;
use std::slice;

use crate::sys;
use crate::sys::SDL_BlendMode;
use crate::sys::SDL_ScaleMode;
use crate::sys::SDL_TextureAccess;
use crate::sys::{
SDL_BlendFactor, SDL_BlendMode, SDL_BlendOperation, SDL_ScaleMode, SDL_TextureAccess,
};

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

/// Blend mode for `Canvas`, `Texture` or `Surface`.
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum BlendMode {
/// no blending (replace destination with source).
None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendMode(pub SDL_BlendMode);

impl fmt::Debug for BlendMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("BlendMode").field(&self.0 .0).finish()
}
}

#[expect(non_upper_case_globals, reason = "deprecated constants")]
impl BlendMode {
/// No blending (replace destination with source).
pub const NONE: Self = Self(SDL_BlendMode::SDL_BLENDMODE_NONE);
#[deprecated(
since = "0.39.0",
note = "use NONE instead, this used to be an enum member"
)]
pub const None: Self = Self::NONE;

/// Alpha blending
///
/// dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
///
/// dstA = srcA + (dstA * (1-srcA))
Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
pub const BLEND: Self = Self(SDL_BlendMode::SDL_BLENDMODE_BLEND);
#[deprecated(
since = "0.39.0",
note = "use BLEND instead, this used to be an enum member"
)]
pub const Blend: Self = Self::BLEND;

/// Additive blending
///
/// dstRGB = (srcRGB * srcA) + dstRGB
///
/// dstA = dstA (keep original alpha)
Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
pub const ADD: Self = Self(SDL_BlendMode::SDL_BLENDMODE_ADD);
#[deprecated(
since = "0.39.0",
note = "use ADD instead, this used to be an enum member"
)]
pub const Add: Self = Self::ADD;

/// Color modulate
///
/// dstRGB = srcRGB * dstRGB
Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
pub const MOD: Self = Self(SDL_BlendMode::SDL_BLENDMODE_MOD);
#[deprecated(
since = "0.39.0",
note = "use MOD instead, this used to be an enum member"
)]
pub const Mod: Self = Self::MOD;

/// Color multiply
Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
pub const MUL: Self = Self(SDL_BlendMode::SDL_BLENDMODE_MUL);
#[deprecated(
since = "0.39.0",
note = "use MUL instead, this used to be an enum member"
)]
pub const Mul: Self = Self::MUL;

/// Invalid blending mode (indicates error)
Invalid = SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
}
pub const INVALID: Self = Self(SDL_BlendMode::SDL_BLENDMODE_INVALID);
#[deprecated(
since = "0.39.0",
note = "use INVALID instead, this used to be an enum member"
)]
pub const Invalid: Self = Self::INVALID;
}

macro_rules! enum_binding {
(
$(#[$meta:meta])*
pub enum $enum:ident = $sdl_enum:ident {$(
#[$($member_meta:meta)*]
$member:ident = $sdl_constant:ident,
)*}
) => {
$(#[$meta])*
///
#[doc = concat!("SDL C API type: [`", stringify!($sdl_enum), "`].")]
/// [`From`] implementations are provided to convert between this type and the C API type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum $enum {$(
$member = $sdl_enum::$sdl_constant as isize,
)*}

impl From<$sdl_enum> for $enum {
fn from(value: $sdl_enum) -> Self {
match value {$(
$sdl_enum::$sdl_constant => Self::$member,
)*}
}
}

impl TryFrom<u32> for BlendMode {
type Error = ();
impl From<$enum> for $sdl_enum {
fn from(value: $enum) -> Self {
match value {$(
$enum::$member => Self::$sdl_constant,
)*}
}
}
};
}

fn try_from(n: u32) -> Result<Self, Self::Error> {
use self::BlendMode::*;
use crate::sys::SDL_BlendMode::*;
enum_binding! {
/// The blend operation used when combining source and destination pixel components.
pub enum BlendOperation = SDL_BlendOperation {
/// dst + src: supported by all renderers
Add = SDL_BLENDOPERATION_ADD,
/// dst - src: supported by D3D9, D3D11, OpenGL, OpenGLES
Subtract = SDL_BLENDOPERATION_SUBTRACT,
/// src - dst: supported by D3D9, D3D11, OpenGL, OpenGLES
RevSubtract = SDL_BLENDOPERATION_REV_SUBTRACT,
/// min(dst, src): supported by D3D9, D3D11
Minimum = SDL_BLENDOPERATION_MINIMUM,
/// max(dst, src): supported by D3D9, D3D11
Maximum = SDL_BLENDOPERATION_MAXIMUM,
}
}

enum_binding! {
/// The normalized factor used to multiply pixel components.
pub enum BlendFactor = SDL_BlendFactor {
/// 0, 0, 0, 0
Zero = SDL_BLENDFACTOR_ZERO,
/// 1, 1, 1, 1
One = SDL_BLENDFACTOR_ONE,
/// srcR, srcG, srcB, srcA
SrcColor = SDL_BLENDFACTOR_SRC_COLOR,
/// 1-srcR, 1-srcG, 1-srcB, 1-srcA
OneMinusSrcColor = SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR,
/// srcA, srcA, srcA, srcA
SrcAlpha = SDL_BLENDFACTOR_SRC_ALPHA,
/// 1-srcA, 1-srcA, 1-srcA, 1-srcA
OneMinusSrcAlpha = SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
/// dstR, dstG, dstB, dstA
DstColor = SDL_BLENDFACTOR_DST_COLOR,
/// 1-dstR, 1-dstG, 1-dstB, 1-dstA
OneMinusDstColor = SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR,
/// dstA, dstA, dstA, dstA
DstAlpha = SDL_BLENDFACTOR_DST_ALPHA,
/// 1-dstA, 1-dstA, 1-dstA, 1-dstA
OneMinusDstAlpha = SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA,
}
}

/// Arguments to [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
///
/// This struct implements [`Default`] with a blend mode equivalent to [`BlendMode::NONE`].
/// Struct update syntax ([Rust Book][book-struct-update], [Rust Reference][reference-struct-update]) can be used to only change a few arguments.
///
/// See [`Self::compose`] for examples.
///
/// [book-struct-update]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
/// [reference-struct-update]: https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax
#[derive(Debug, Clone, Copy)]
pub struct CustomBlendMode {
pub src_color_factor: BlendFactor,
pub dst_color_factor: BlendFactor,
pub color_operation: BlendOperation,
pub src_alpha_factor: BlendFactor,
pub dst_alpha_factor: BlendFactor,
pub alpha_operation: BlendOperation,
}

match n {
x if x == SDL_BLENDMODE_NONE as u32 => Ok(None),
x if x == SDL_BLENDMODE_BLEND as u32 => Ok(Blend),
x if x == SDL_BLENDMODE_ADD as u32 => Ok(Add),
x if x == SDL_BLENDMODE_MOD as u32 => Ok(Mod),
x if x == SDL_BLENDMODE_MUL as u32 => Ok(Mul),
x if x == SDL_BLENDMODE_INVALID as u32 => Ok(Invalid),
_ => Err(()),
impl Default for CustomBlendMode {
fn default() -> Self {
Self {
src_color_factor: BlendFactor::One,
dst_color_factor: BlendFactor::Zero,
color_operation: BlendOperation::Add,
src_alpha_factor: BlendFactor::One,
dst_alpha_factor: BlendFactor::Zero,
alpha_operation: BlendOperation::Add,
}
}
}

impl CustomBlendMode {
/// Compose a custom blend mode for renderers.
///
/// # Examples
///
/// ```
/// use sdl2::render::{BlendFactor, BlendOperation, CustomBlendMode};
///
/// let no_blending = CustomBlendMode {
/// src_color_factor: BlendFactor::One,
/// dst_color_factor: BlendFactor::Zero,
/// color_operation: BlendOperation::Add,
/// src_alpha_factor: BlendFactor::One,
/// dst_alpha_factor: BlendFactor::Zero,
/// alpha_operation: BlendOperation::Add,
/// }.compose();
///
/// let ignore_alpha = CustomBlendMode {
/// src_alpha_factor: BlendFactor::Zero,
/// dst_alpha_factor: BlendFactor::One,
/// ..Default::default()
/// }.compose();
/// ```
///
/// See [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
#[doc(alias = "SDL_ComposeCustomBlendMode")]
pub fn compose(self) -> BlendMode {
let Self {
src_color_factor,
dst_color_factor,
color_operation,
src_alpha_factor,
dst_alpha_factor,
alpha_operation,
} = self;

BlendMode(unsafe {
sys::SDL_ComposeCustomBlendMode(
src_color_factor.into(),
dst_color_factor.into(),
color_operation.into(),
src_alpha_factor.into(),
dst_alpha_factor.into(),
alpha_operation.into(),
)
})
}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum ScaleMode {
/// nearest pixel sampling. default
Expand Down Expand Up @@ -1098,8 +1280,7 @@ impl<T: RenderTarget> Canvas<T> {
/// Sets the blend mode used for drawing operations (Fill and Line).
#[doc(alias = "SDL_SetRenderDrawBlendMode")]
pub fn set_blend_mode(&mut self, blend: BlendMode) {
let ret =
unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32)) };
let ret = unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, blend.0) };
// Should only fail on an invalid renderer
if ret != 0 {
panic!("{}", get_error())
Expand All @@ -1115,8 +1296,7 @@ impl<T: RenderTarget> Canvas<T> {
if ret != 0 {
panic!("{}", get_error())
} else {
let blend = unsafe { blend.assume_init() };
BlendMode::try_from(blend as u32).unwrap()
BlendMode(unsafe { blend.assume_init() })
}
}

Expand Down Expand Up @@ -2541,7 +2721,7 @@ impl InternalTexture {

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

if ret != 0 {
panic!("Error setting blend: {}", get_error())
Expand All @@ -2557,8 +2737,7 @@ impl InternalTexture {
if ret != 0 {
panic!("{}", get_error())
} else {
let blend = unsafe { blend.assume_init() };
BlendMode::try_from(blend as u32).unwrap()
BlendMode(unsafe { blend.assume_init() })
}
}

Expand Down
Loading
Loading