Skip to content
Open
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
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ path = "examples/custom_material.rs"
name = "input"
path = "examples/input.rs"

[[example]]
name = "blend_modes"
path = "examples/blend_modes.rs"

[profile.wasm-release]
inherits = "release"
opt-level = "z"
Expand Down
2 changes: 1 addition & 1 deletion crates/processing_ffi/src/color.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy::color::{LinearRgba, Srgba};
use bevy::color::LinearRgba;
use processing::prelude::color::{ColorMode, ColorSpace};

/// A color with 4 float components and its color space.
Expand Down
69 changes: 69 additions & 0 deletions crates/processing_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,36 @@ pub extern "C" fn processing_shear_y(graphics_id: u64, angle: f32) {
error::check(|| graphics_record_command(graphics_entity, DrawCommand::ShearY { angle }));
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_set_blend_mode(graphics_id: u64, mode: u8) {
error::clear_error();
let graphics_entity = Entity::from_bits(graphics_id);
error::check(|| {
let blend_state = processing::prelude::BlendMode::try_from(mode)?.to_blend_state();
graphics_record_command(graphics_entity, DrawCommand::BlendMode(blend_state))
});
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_set_custom_blend_mode(
graphics_id: u64,
color_src: u8,
color_dst: u8,
color_op: u8,
alpha_src: u8,
alpha_dst: u8,
alpha_op: u8,
) {
error::clear_error();
let graphics_entity = Entity::from_bits(graphics_id);
error::check(|| {
let blend_state = custom_blend_state(
color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op,
)?;
graphics_record_command(graphics_entity, DrawCommand::BlendMode(Some(blend_state)))
});
}

/// Draw a rectangle.
///
/// SAFETY:
Expand Down Expand Up @@ -767,6 +797,35 @@ pub const PROCESSING_STROKE_JOIN_ROUND: u8 = 0;
pub const PROCESSING_STROKE_JOIN_MITER: u8 = 1;
pub const PROCESSING_STROKE_JOIN_BEVEL: u8 = 2;

pub const PROCESSING_BLEND_MODE_BLEND: u8 = 0;
pub const PROCESSING_BLEND_MODE_ADD: u8 = 1;
pub const PROCESSING_BLEND_MODE_SUBTRACT: u8 = 2;
pub const PROCESSING_BLEND_MODE_DARKEST: u8 = 3;
pub const PROCESSING_BLEND_MODE_LIGHTEST: u8 = 4;
pub const PROCESSING_BLEND_MODE_DIFFERENCE: u8 = 5;
pub const PROCESSING_BLEND_MODE_EXCLUSION: u8 = 6;
pub const PROCESSING_BLEND_MODE_MULTIPLY: u8 = 7;
pub const PROCESSING_BLEND_MODE_SCREEN: u8 = 8;
pub const PROCESSING_BLEND_MODE_REPLACE: u8 = 9;

pub const PROCESSING_BLEND_FACTOR_ZERO: u8 = 0;
pub const PROCESSING_BLEND_FACTOR_ONE: u8 = 1;
pub const PROCESSING_BLEND_FACTOR_SRC: u8 = 2;
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_SRC: u8 = 3;
pub const PROCESSING_BLEND_FACTOR_SRC_ALPHA: u8 = 4;
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: u8 = 5;
pub const PROCESSING_BLEND_FACTOR_DST: u8 = 6;
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_DST: u8 = 7;
pub const PROCESSING_BLEND_FACTOR_DST_ALPHA: u8 = 8;
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: u8 = 9;
pub const PROCESSING_BLEND_FACTOR_SRC_ALPHA_SATURATED: u8 = 10;

pub const PROCESSING_BLEND_OP_ADD: u8 = 0;
pub const PROCESSING_BLEND_OP_SUBTRACT: u8 = 1;
pub const PROCESSING_BLEND_OP_REVERSE_SUBTRACT: u8 = 2;
pub const PROCESSING_BLEND_OP_MIN: u8 = 3;
pub const PROCESSING_BLEND_OP_MAX: u8 = 4;

#[unsafe(no_mangle)]
pub extern "C" fn processing_geometry_layout_create() -> u64 {
error::clear_error();
Expand Down Expand Up @@ -1564,6 +1623,16 @@ pub extern "C" fn processing_key_is_down(key_code: u32) -> bool {
.unwrap_or(false)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_key_just_pressed(key_code: u32) -> bool {
error::clear_error();
error::check(|| {
let kc = key_code_from_u32(key_code)?;
input_key_just_pressed(kc)
})
.unwrap_or(false)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_key() -> u32 {
error::clear_error();
Expand Down
9 changes: 9 additions & 0 deletions crates/processing_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@ pub fn input_key_is_pressed() -> error::Result<bool> {
})
}

pub fn input_key_just_pressed(key_code: KeyCode) -> error::Result<bool> {
app_mut(|app| {
Ok(app
.world()
.resource::<ButtonInput<KeyCode>>()
.just_pressed(key_code))
})
}

pub fn input_key_is_down(key_code: KeyCode) -> error::Result<bool> {
app_mut(|app| {
Ok(app
Expand Down
30 changes: 30 additions & 0 deletions crates/processing_pyo3/examples/blend_modes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from mewnala import *

MODES = [BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, REPLACE]
index = 0

def setup():
size(500, 500)

def draw():
global index

if key_just_pressed(RIGHT_ARROW) or key_just_pressed(SPACE):
index = (index + 1) % len(MODES)
elif key_just_pressed(LEFT_ARROW):
index = (index - 1) % len(MODES)

background(38)
no_stroke()
blend_mode(MODES[index])

fill(230, 51, 51, 191)
rect(80, 100, 200, 250)

fill(51, 204, 51, 191)
rect(180, 80, 200, 250)

fill(51, 77, 230, 191)
rect(130, 200, 200, 200)

run()
88 changes: 85 additions & 3 deletions crates/processing_pyo3/src/graphics.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use crate::color::{ColorMode, extract_color_with_mode};
use crate::color::{ColorMode, extract_color_with_mode};
use crate::glfw::GlfwContext;
use crate::glfw::GlfwContext;
use crate::input;
use crate::math::{extract_vec2, extract_vec3, extract_vec4};
use crate::math::{extract_vec2, extract_vec3, extract_vec4};
use bevy::{
color::{ColorToPacked, Srgba},
math::Vec4,
Expand All @@ -18,6 +15,86 @@ use pyo3::{
types::{PyDict, PyTuple},
};

#[pyclass(name = "BlendMode", from_py_object)]
#[derive(Clone)]
pub struct PyBlendMode {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this named PyBlendMode do you think we want to move towards this schema?

pub(crate) blend_state: Option<bevy::render::render_resource::BlendState>,
name: Option<&'static str>,
}

impl PyBlendMode {
pub(crate) fn from_preset(mode: BlendMode) -> Self {
Self {
blend_state: mode.to_blend_state(),
name: Some(mode.name()),
}
}
}

#[pymethods]
impl PyBlendMode {
#[new]
#[pyo3(signature = (*, color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op))]
fn new(
color_src: u8,
color_dst: u8,
color_op: u8,
alpha_src: u8,
alpha_dst: u8,
alpha_op: u8,
) -> PyResult<Self> {
let blend_state = custom_blend_state(
color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op,
)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
Ok(Self {
blend_state: Some(blend_state),
name: None,
})
}

fn __repr__(&self) -> String {
match self.name {
Some(name) => format!("BlendMode.{name}"),
None => "BlendMode(custom)".to_string(),
}
}

#[classattr]
const ZERO: u8 = 0;
#[classattr]
const ONE: u8 = 1;
#[classattr]
const SRC_COLOR: u8 = 2;
#[classattr]
const ONE_MINUS_SRC_COLOR: u8 = 3;
#[classattr]
const SRC_ALPHA: u8 = 4;
#[classattr]
const ONE_MINUS_SRC_ALPHA: u8 = 5;
#[classattr]
const DST_COLOR: u8 = 6;
#[classattr]
const ONE_MINUS_DST_COLOR: u8 = 7;
#[classattr]
const DST_ALPHA: u8 = 8;
#[classattr]
const ONE_MINUS_DST_ALPHA: u8 = 9;
#[classattr]
const SRC_ALPHA_SATURATED: u8 = 10;

#[classattr]
const OP_ADD: u8 = 0;
#[classattr]
const OP_SUBTRACT: u8 = 1;
#[classattr]
const OP_REVERSE_SUBTRACT: u8 = 2;
#[classattr]
const OP_MIN: u8 = 3;
#[classattr]
const OP_MAX: u8 = 4;
}

#[pyclass(unsendable)]
pub struct Surface {
pub(crate) entity: Entity,
Expand Down Expand Up @@ -517,6 +594,11 @@ impl Graphics {
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn blend_mode(&self, mode: &PyBlendMode) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::BlendMode(mode.blend_state))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn set_material(&self, material: &crate::material::Material) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
Expand Down
6 changes: 6 additions & 0 deletions crates/processing_pyo3/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ pub fn key_is_down(key_code: u32) -> PyResult<bool> {
processing::prelude::input_key_is_down(kc).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn key_just_pressed(key_code: u32) -> PyResult<bool> {
let kc = u32_to_key_code(key_code)?;
processing::prelude::input_key_just_pressed(kc)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn key() -> PyResult<Option<String>> {
processing::prelude::input_key()
.map(|opt| opt.map(String::from))
Expand Down
36 changes: 35 additions & 1 deletion crates/processing_pyo3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ pub(crate) mod shader;
#[cfg(feature = "webcam")]
mod webcam;

use graphics::{Geometry, Graphics, Image, Light, Topology, get_graphics, get_graphics_mut};
use graphics::{
Geometry, Graphics, Image, Light, PyBlendMode, Topology, get_graphics, get_graphics_mut,
};
use material::Material;

use pyo3::{
Expand Down Expand Up @@ -127,6 +129,8 @@ mod mewnala {
#[pymodule_export]
use super::Material;
#[pymodule_export]
use super::PyBlendMode;
#[pymodule_export]
use super::Shader;
#[pymodule_export]
use super::Topology;
Expand Down Expand Up @@ -341,6 +345,25 @@ mod mewnala {
#[pymodule_export]
const XYZ: u8 = 9;

#[pymodule_init]
fn init(module: &Bound<'_, PyModule>) -> PyResult<()> {
use processing::prelude::BlendMode;
module.add("BLEND", PyBlendMode::from_preset(BlendMode::Blend))?;
module.add("ADD", PyBlendMode::from_preset(BlendMode::Add))?;
module.add("SUBTRACT", PyBlendMode::from_preset(BlendMode::Subtract))?;
module.add("DARKEST", PyBlendMode::from_preset(BlendMode::Darkest))?;
module.add("LIGHTEST", PyBlendMode::from_preset(BlendMode::Lightest))?;
module.add(
"DIFFERENCE",
PyBlendMode::from_preset(BlendMode::Difference),
)?;
module.add("EXCLUSION", PyBlendMode::from_preset(BlendMode::Exclusion))?;
module.add("MULTIPLY", PyBlendMode::from_preset(BlendMode::Multiply))?;
module.add("SCREEN", PyBlendMode::from_preset(BlendMode::Screen))?;
module.add("REPLACE", PyBlendMode::from_preset(BlendMode::Replace))?;
Ok(())
}

#[pymodule]
mod math {
use super::*;
Expand Down Expand Up @@ -804,6 +827,12 @@ mod mewnala {
graphics!(module).stroke_join(join)
}

#[pyfunction]
#[pyo3(pass_module, signature = (mode))]
fn blend_mode(module: &Bound<'_, PyModule>, mode: &Bound<'_, PyBlendMode>) -> PyResult<()> {
graphics!(module).blend_mode(&*mode.extract::<PyRef<PyBlendMode>>()?)
}

#[pyfunction]
#[pyo3(pass_module, signature = (x, y, w, h, tl=0.0, tr=0.0, br=0.0, bl=0.0))]
fn rect(
Expand Down Expand Up @@ -979,4 +1008,9 @@ mod mewnala {
fn key_is_down(key_code: u32) -> PyResult<bool> {
input::key_is_down(key_code)
}

#[pyfunction]
fn key_just_pressed(key_code: u32) -> PyResult<bool> {
input::key_just_pressed(key_code)
}
}
6 changes: 3 additions & 3 deletions crates/processing_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct ProcessingRenderPlugin;

impl Plugin for ProcessingRenderPlugin {
fn build(&self, app: &mut App) {
use render::material::{add_custom_materials, add_standard_materials};
use render::material::{add_custom_materials, add_processing_materials};
use render::{activate_cameras, clear_transient_meshes, flush_draw_commands};

let config = app.world().resource::<Config>().clone();
Expand Down Expand Up @@ -66,7 +66,7 @@ impl Plugin for ProcessingRenderPlugin {
surface::SurfacePlugin,
geometry::GeometryPlugin,
light::LightPlugin,
material::MaterialPlugin,
material::ProcessingMaterialPlugin,
bevy::pbr::wireframe::WireframePlugin::default(),
material::custom::CustomMaterialPlugin,
));
Expand All @@ -76,7 +76,7 @@ impl Plugin for ProcessingRenderPlugin {
Update,
(
flush_draw_commands,
add_standard_materials,
add_processing_materials,
add_custom_materials,
)
.chain()
Expand Down
Loading
Loading