Skip to content

Commit 03ff673

Browse files
committed
Merge.
2 parents 69f5227 + ee7a4aa commit 03ff673

File tree

18 files changed

+854
-70
lines changed

18 files changed

+854
-70
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ path = "examples/curves.rs"
144144
name = "shapes"
145145
path = "examples/shapes.rs"
146146

147+
[[example]]
148+
name = "blend_modes"
149+
path = "examples/blend_modes.rs"
150+
147151
[profile.wasm-release]
148152
inherits = "release"
149153
opt-level = "z"

crates/processing_ffi/src/lib.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,36 @@ pub extern "C" fn processing_shear_y(graphics_id: u64, angle: f32) {
492492
error::check(|| graphics_record_command(graphics_entity, DrawCommand::ShearY { angle }));
493493
}
494494

495+
#[unsafe(no_mangle)]
496+
pub extern "C" fn processing_set_blend_mode(graphics_id: u64, mode: u8) {
497+
error::clear_error();
498+
let graphics_entity = Entity::from_bits(graphics_id);
499+
error::check(|| {
500+
let blend_state = processing::prelude::BlendMode::try_from(mode)?.to_blend_state();
501+
graphics_record_command(graphics_entity, DrawCommand::BlendMode(blend_state))
502+
});
503+
}
504+
505+
#[unsafe(no_mangle)]
506+
pub extern "C" fn processing_set_custom_blend_mode(
507+
graphics_id: u64,
508+
color_src: u8,
509+
color_dst: u8,
510+
color_op: u8,
511+
alpha_src: u8,
512+
alpha_dst: u8,
513+
alpha_op: u8,
514+
) {
515+
error::clear_error();
516+
let graphics_entity = Entity::from_bits(graphics_id);
517+
error::check(|| {
518+
let blend_state = custom_blend_state(
519+
color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op,
520+
)?;
521+
graphics_record_command(graphics_entity, DrawCommand::BlendMode(Some(blend_state)))
522+
});
523+
}
524+
495525
/// Draw a rectangle.
496526
///
497527
/// SAFETY:
@@ -1215,6 +1245,35 @@ pub const PROCESSING_STROKE_JOIN_ROUND: u8 = 0;
12151245
pub const PROCESSING_STROKE_JOIN_MITER: u8 = 1;
12161246
pub const PROCESSING_STROKE_JOIN_BEVEL: u8 = 2;
12171247

1248+
pub const PROCESSING_BLEND_MODE_BLEND: u8 = 0;
1249+
pub const PROCESSING_BLEND_MODE_ADD: u8 = 1;
1250+
pub const PROCESSING_BLEND_MODE_SUBTRACT: u8 = 2;
1251+
pub const PROCESSING_BLEND_MODE_DARKEST: u8 = 3;
1252+
pub const PROCESSING_BLEND_MODE_LIGHTEST: u8 = 4;
1253+
pub const PROCESSING_BLEND_MODE_DIFFERENCE: u8 = 5;
1254+
pub const PROCESSING_BLEND_MODE_EXCLUSION: u8 = 6;
1255+
pub const PROCESSING_BLEND_MODE_MULTIPLY: u8 = 7;
1256+
pub const PROCESSING_BLEND_MODE_SCREEN: u8 = 8;
1257+
pub const PROCESSING_BLEND_MODE_REPLACE: u8 = 9;
1258+
1259+
pub const PROCESSING_BLEND_FACTOR_ZERO: u8 = 0;
1260+
pub const PROCESSING_BLEND_FACTOR_ONE: u8 = 1;
1261+
pub const PROCESSING_BLEND_FACTOR_SRC: u8 = 2;
1262+
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_SRC: u8 = 3;
1263+
pub const PROCESSING_BLEND_FACTOR_SRC_ALPHA: u8 = 4;
1264+
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: u8 = 5;
1265+
pub const PROCESSING_BLEND_FACTOR_DST: u8 = 6;
1266+
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_DST: u8 = 7;
1267+
pub const PROCESSING_BLEND_FACTOR_DST_ALPHA: u8 = 8;
1268+
pub const PROCESSING_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: u8 = 9;
1269+
pub const PROCESSING_BLEND_FACTOR_SRC_ALPHA_SATURATED: u8 = 10;
1270+
1271+
pub const PROCESSING_BLEND_OP_ADD: u8 = 0;
1272+
pub const PROCESSING_BLEND_OP_SUBTRACT: u8 = 1;
1273+
pub const PROCESSING_BLEND_OP_REVERSE_SUBTRACT: u8 = 2;
1274+
pub const PROCESSING_BLEND_OP_MIN: u8 = 3;
1275+
pub const PROCESSING_BLEND_OP_MAX: u8 = 4;
1276+
12181277
#[unsafe(no_mangle)]
12191278
pub extern "C" fn processing_geometry_layout_create() -> u64 {
12201279
error::clear_error();
@@ -2012,6 +2071,16 @@ pub extern "C" fn processing_key_is_down(key_code: u32) -> bool {
20122071
.unwrap_or(false)
20132072
}
20142073

2074+
#[unsafe(no_mangle)]
2075+
pub extern "C" fn processing_key_just_pressed(key_code: u32) -> bool {
2076+
error::clear_error();
2077+
error::check(|| {
2078+
let kc = key_code_from_u32(key_code)?;
2079+
input_key_just_pressed(kc)
2080+
})
2081+
.unwrap_or(false)
2082+
}
2083+
20152084
#[unsafe(no_mangle)]
20162085
pub extern "C" fn processing_key() -> u32 {
20172086
error::clear_error();

crates/processing_input/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,15 @@ pub fn input_key_is_pressed() -> error::Result<bool> {
241241
})
242242
}
243243

244+
pub fn input_key_just_pressed(key_code: KeyCode) -> error::Result<bool> {
245+
app_mut(|app| {
246+
Ok(app
247+
.world()
248+
.resource::<ButtonInput<KeyCode>>()
249+
.just_pressed(key_code))
250+
})
251+
}
252+
244253
pub fn input_key_is_down(key_code: KeyCode) -> error::Result<bool> {
245254
app_mut(|app| {
246255
Ok(app
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from mewnala import *
2+
3+
MODES = [BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, REPLACE]
4+
index = 0
5+
6+
def setup():
7+
size(500, 500)
8+
9+
def draw():
10+
global index
11+
12+
if key_just_pressed(RIGHT_ARROW) or key_just_pressed(SPACE):
13+
index = (index + 1) % len(MODES)
14+
elif key_just_pressed(LEFT_ARROW):
15+
index = (index - 1) % len(MODES)
16+
17+
background(38)
18+
no_stroke()
19+
blend_mode(MODES[index])
20+
21+
fill(230, 51, 51, 191)
22+
rect(80, 100, 200, 250)
23+
24+
fill(51, 204, 51, 191)
25+
rect(180, 80, 200, 250)
26+
27+
fill(51, 77, 230, 191)
28+
rect(130, 200, 200, 200)
29+
30+
run()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from mewnala import *
2+
3+
geometry = None
4+
5+
6+
def setup():
7+
global geometry
8+
size(640, 480)
9+
mode_3d()
10+
11+
geometry = Geometry()
12+
13+
geometry.normal(0.0, 0.0, 1.0)
14+
15+
geometry.uv(0.0, 0.0)
16+
geometry.vertex(-80.0, -80.0, 0.0)
17+
18+
geometry.uv(1.0, 0.0)
19+
geometry.vertex(80.0, -80.0, 0.0)
20+
21+
geometry.uv(0.5, 1.0)
22+
geometry.vertex(0.0, 80.0, 0.0)
23+
24+
geometry.index(0)
25+
geometry.index(1)
26+
geometry.index(2)
27+
28+
print("vertex_count =", geometry.vertex_count())
29+
30+
31+
def draw():
32+
background(220)
33+
camera_position(0.0, 0.0, 200.0)
34+
camera_look_at(0.0, 0.0, 0.0)
35+
draw_geometry(geometry)
36+
37+
38+
run()

crates/processing_pyo3/src/graphics.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,86 @@ use pyo3::{
1515
types::{PyDict, PyTuple},
1616
};
1717

18+
#[pyclass(name = "BlendMode", from_py_object)]
19+
#[derive(Clone)]
20+
pub struct PyBlendMode {
21+
pub(crate) blend_state: Option<bevy::render::render_resource::BlendState>,
22+
name: Option<&'static str>,
23+
}
24+
25+
impl PyBlendMode {
26+
pub(crate) fn from_preset(mode: BlendMode) -> Self {
27+
Self {
28+
blend_state: mode.to_blend_state(),
29+
name: Some(mode.name()),
30+
}
31+
}
32+
}
33+
34+
#[pymethods]
35+
impl PyBlendMode {
36+
#[new]
37+
#[pyo3(signature = (*, color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op))]
38+
fn new(
39+
color_src: u8,
40+
color_dst: u8,
41+
color_op: u8,
42+
alpha_src: u8,
43+
alpha_dst: u8,
44+
alpha_op: u8,
45+
) -> PyResult<Self> {
46+
let blend_state = custom_blend_state(
47+
color_src, color_dst, color_op, alpha_src, alpha_dst, alpha_op,
48+
)
49+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
50+
Ok(Self {
51+
blend_state: Some(blend_state),
52+
name: None,
53+
})
54+
}
55+
56+
fn __repr__(&self) -> String {
57+
match self.name {
58+
Some(name) => format!("BlendMode.{name}"),
59+
None => "BlendMode(custom)".to_string(),
60+
}
61+
}
62+
63+
#[classattr]
64+
const ZERO: u8 = 0;
65+
#[classattr]
66+
const ONE: u8 = 1;
67+
#[classattr]
68+
const SRC_COLOR: u8 = 2;
69+
#[classattr]
70+
const ONE_MINUS_SRC_COLOR: u8 = 3;
71+
#[classattr]
72+
const SRC_ALPHA: u8 = 4;
73+
#[classattr]
74+
const ONE_MINUS_SRC_ALPHA: u8 = 5;
75+
#[classattr]
76+
const DST_COLOR: u8 = 6;
77+
#[classattr]
78+
const ONE_MINUS_DST_COLOR: u8 = 7;
79+
#[classattr]
80+
const DST_ALPHA: u8 = 8;
81+
#[classattr]
82+
const ONE_MINUS_DST_ALPHA: u8 = 9;
83+
#[classattr]
84+
const SRC_ALPHA_SATURATED: u8 = 10;
85+
86+
#[classattr]
87+
const OP_ADD: u8 = 0;
88+
#[classattr]
89+
const OP_SUBTRACT: u8 = 1;
90+
#[classattr]
91+
const OP_REVERSE_SUBTRACT: u8 = 2;
92+
#[classattr]
93+
const OP_MIN: u8 = 3;
94+
#[classattr]
95+
const OP_MAX: u8 = 4;
96+
}
97+
1898
#[pyclass(unsendable)]
1999
pub struct Surface {
20100
pub(crate) entity: Entity,
@@ -149,6 +229,12 @@ impl Geometry {
149229
geometry_vertex(self.entity, v).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
150230
}
151231

232+
#[pyo3(signature = (*args))]
233+
pub fn uv(&self, args: &Bound<'_, PyTuple>) -> PyResult<()> {
234+
let v = extract_vec2(args)?;
235+
geometry_uv(self.entity, v.x, v.y).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
236+
}
237+
152238
pub fn index(&self, i: u32) -> PyResult<()> {
153239
geometry_index(self.entity, i).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
154240
}
@@ -158,6 +244,10 @@ impl Geometry {
158244
let v = extract_vec3(args)?;
159245
geometry_set_vertex(self.entity, i, v).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
160246
}
247+
248+
pub fn vertex_count(&self) -> PyResult<u32> {
249+
geometry_vertex_count(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
250+
}
161251
}
162252

163253
#[pyclass(unsendable)]
@@ -837,6 +927,11 @@ impl Graphics {
837927
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
838928
}
839929

930+
pub fn blend_mode(&self, mode: &PyBlendMode) -> PyResult<()> {
931+
graphics_record_command(self.entity, DrawCommand::BlendMode(mode.blend_state))
932+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
933+
}
934+
840935
pub fn set_material(&self, material: &crate::material::Material) -> PyResult<()> {
841936
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
842937
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))

crates/processing_pyo3/src/input.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ pub fn key_is_down(key_code: u32) -> PyResult<bool> {
6262
processing::prelude::input_key_is_down(kc).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
6363
}
6464

65+
pub fn key_just_pressed(key_code: u32) -> PyResult<bool> {
66+
let kc = u32_to_key_code(key_code)?;
67+
processing::prelude::input_key_just_pressed(kc)
68+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
69+
}
70+
6571
pub fn key() -> PyResult<Option<String>> {
6672
processing::prelude::input_key()
6773
.map(|opt| opt.map(String::from))

crates/processing_pyo3/src/lib.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ pub(crate) mod shader;
2020
#[cfg(feature = "webcam")]
2121
mod webcam;
2222

23-
use graphics::{Geometry, Graphics, Image, Light, Topology, get_graphics, get_graphics_mut};
23+
use graphics::{
24+
Geometry, Graphics, Image, Light, PyBlendMode, Topology, get_graphics, get_graphics_mut,
25+
};
2426
use material::Material;
2527

2628
use pyo3::{
@@ -127,6 +129,8 @@ mod mewnala {
127129
#[pymodule_export]
128130
use super::Material;
129131
#[pymodule_export]
132+
use super::PyBlendMode;
133+
#[pymodule_export]
130134
use super::Shader;
131135
#[pymodule_export]
132136
use super::Topology;
@@ -379,6 +383,25 @@ mod mewnala {
379383
#[pymodule_export]
380384
const XYZ: u8 = 9;
381385

386+
#[pymodule_init]
387+
fn init(module: &Bound<'_, PyModule>) -> PyResult<()> {
388+
use processing::prelude::BlendMode;
389+
module.add("BLEND", PyBlendMode::from_preset(BlendMode::Blend))?;
390+
module.add("ADD", PyBlendMode::from_preset(BlendMode::Add))?;
391+
module.add("SUBTRACT", PyBlendMode::from_preset(BlendMode::Subtract))?;
392+
module.add("DARKEST", PyBlendMode::from_preset(BlendMode::Darkest))?;
393+
module.add("LIGHTEST", PyBlendMode::from_preset(BlendMode::Lightest))?;
394+
module.add(
395+
"DIFFERENCE",
396+
PyBlendMode::from_preset(BlendMode::Difference),
397+
)?;
398+
module.add("EXCLUSION", PyBlendMode::from_preset(BlendMode::Exclusion))?;
399+
module.add("MULTIPLY", PyBlendMode::from_preset(BlendMode::Multiply))?;
400+
module.add("SCREEN", PyBlendMode::from_preset(BlendMode::Screen))?;
401+
module.add("REPLACE", PyBlendMode::from_preset(BlendMode::Replace))?;
402+
Ok(())
403+
}
404+
382405
#[pymodule]
383406
mod math {
384407
use super::*;
@@ -848,6 +871,12 @@ mod mewnala {
848871
graphics!(module).stroke_join(join)
849872
}
850873

874+
#[pyfunction]
875+
#[pyo3(pass_module, signature = (mode))]
876+
fn blend_mode(module: &Bound<'_, PyModule>, mode: &Bound<'_, PyBlendMode>) -> PyResult<()> {
877+
graphics!(module).blend_mode(&*mode.extract::<PyRef<PyBlendMode>>()?)
878+
}
879+
851880
#[pyfunction]
852881
#[pyo3(pass_module, signature = (x, y, w, h, tl=0.0, tr=0.0, br=0.0, bl=0.0))]
853882
fn rect(
@@ -1297,4 +1326,9 @@ mod mewnala {
12971326
fn key_is_down(key_code: u32) -> PyResult<bool> {
12981327
input::key_is_down(key_code)
12991328
}
1329+
1330+
#[pyfunction]
1331+
fn key_just_pressed(key_code: u32) -> PyResult<bool> {
1332+
input::key_just_pressed(key_code)
1333+
}
13001334
}

0 commit comments

Comments
 (0)