Skip to content

Commit 02ffebd

Browse files
authored
Misc fixes (#156)
1 parent 3c476d1 commit 02ffebd

7 files changed

Lines changed: 100 additions & 41 deletions

File tree

crates/processing_core/src/lib.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,21 @@ thread_local! {
1414
}
1515

1616
pub fn app_mut<T>(cb: impl FnOnce(&mut App) -> error::Result<T>) -> error::Result<T> {
17-
let res = APP.with(|app_cell| {
18-
let mut app_borrow = app_cell.borrow_mut();
17+
// `try_with` so a `Drop` running after the TLS is destroyed sees an
18+
// `AppAccess` error rather than panicking
19+
let res = APP.try_with(|app_cell| {
20+
let mut app_borrow = app_cell
21+
.try_borrow_mut()
22+
.map_err(|_| error::ProcessingError::AppAccess)?;
1923
let app = app_borrow
2024
.as_mut()
2125
.ok_or(error::ProcessingError::AppAccess)?;
2226
cb(app)
23-
})?;
24-
Ok(res)
27+
});
28+
match res {
29+
Ok(inner) => inner,
30+
Err(_) => Err(error::ProcessingError::AppAccess),
31+
}
2532
}
2633

2734
pub fn is_already_init() -> error::Result<bool> {

crates/processing_pyo3/examples/camera_controllers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def setup():
88
mode_3d()
99
orbit_camera()
1010

11-
dir_light = create_directional_light((1.0, 0.98, 0.95), 1500.0)
11+
dir_light = directional_light((1.0, 0.98, 0.95), 1500.0)
1212
dir_light.position(300.0, 400.0, 300.0)
1313
dir_light.look_at(0.0, 0.0, 0.0)
1414

crates/processing_pyo3/examples/lights.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ def setup():
77
mode_3d()
88

99
# Directional Light
10-
dir_light = create_directional_light((0.5, 0.24, 1.0), 1500.0)
10+
dir_light = directional_light((0.5, 0.24, 1.0), 1500.0)
1111

1212
# Point Lights
13-
point_light_a = create_point_light((1.0, 0.5, 0.25), 1000000.0, 200.0, 0.5)
13+
point_light_a = point_light((1.0, 0.5, 0.25), 1000000.0, 200.0, 0.5)
1414
point_light_a.position(-25.0, 5.0, 51.0)
1515
point_light_a.look_at(0.0, 0.0, 0.0)
1616

17-
point_light_b = create_point_light((0.0, 0.5, 0.75), 2000000.0, 200.0, 0.25)
17+
point_light_b = point_light((0.0, 0.5, 0.75), 2000000.0, 200.0, 0.25)
1818
point_light_b.position(0.0, 5.0, 50.5)
1919
point_light_b.look_at(0.0, 0.0, 0.0)
2020

2121
# Spot Light
22-
spot_light = create_spot_light((0.25, 0.8, 0.19), 15.0 * 1000000.0, 200.0, 0.84, 0.0, 0.7854)
22+
spot_light = spot_light((0.25, 0.8, 0.19), 15.0 * 1000000.0, 200.0, 0.84, 0.0, 0.7854)
2323
spot_light.position(40.0, 0.0, 70.0)
2424
spot_light.look_at(0.0, 0.0, 0.0)
2525

crates/processing_pyo3/examples/materials.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ def setup():
77
size(800, 600)
88
mode_3d()
99

10-
dir_light = create_directional_light((1.0, 0.98, 0.95), 1500.0)
11-
point_light = create_point_light((1.0, 1.0, 1.0), 100000.0, 800.0, 0.0)
10+
dir_light = directional_light((1.0, 0.98, 0.95), 1500.0)
11+
point_light = point_light((1.0, 1.0, 1.0), 100000.0, 800.0, 0.0)
1212
point_light.position(200.0, 200.0, 400.0)
1313

1414
mat = Material()

crates/processing_pyo3/src/lib.rs

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,19 @@ mod mewnala {
673673
#[pymodule_export]
674674
use crate::color::PyColor;
675675

676+
#[pyfunction(name = "color")]
677+
#[pyo3(signature = (*args))]
678+
fn color_ctor(py: Python<'_>, args: &Bound<'_, PyTuple>) -> PyResult<PyColor> {
679+
let parent = py.import("mewnala.mewnala")?;
680+
match get_graphics(&parent)? {
681+
Some(g) => g.color(args),
682+
None => {
683+
let mode = crate::color::ColorMode::default();
684+
crate::color::extract_color_with_mode(args, &mode).map(PyColor::from)
685+
}
686+
}
687+
}
688+
676689
#[pyfunction]
677690
fn hex(s: &str) -> PyResult<PyColor> {
678691
PyColor::hex(s)
@@ -1011,7 +1024,7 @@ mod mewnala {
10111024
return Ok(());
10121025
}
10131026

1014-
Python::attach(|py| {
1027+
let result: PyResult<()> = Python::attach(|py| {
10151028
let builtins = PyModule::import(py, "builtins")?;
10161029
let locals = builtins.getattr("locals")?.call0()?;
10171030

@@ -1132,7 +1145,13 @@ mod mewnala {
11321145
}
11331146

11341147
Ok(())
1135-
})
1148+
});
1149+
1150+
// tear the app down here while the TLS is still alive; the eager
1151+
// TLS destructor aborts inside a Bevy resource drop
1152+
let _ = ::processing::exit(0);
1153+
1154+
result
11361155
}
11371156

11381157
#[pyfunction]
@@ -1290,21 +1309,6 @@ mod mewnala {
12901309
graphics!(module).draw_geometry(&*geometry.extract::<PyRef<Geometry>>()?)
12911310
}
12921311

1293-
#[pyfunction(name = "color")]
1294-
#[pyo3(pass_module, signature = (*args))]
1295-
fn create_color(
1296-
module: &Bound<'_, PyModule>,
1297-
args: &Bound<'_, PyTuple>,
1298-
) -> PyResult<super::color::PyColor> {
1299-
match get_graphics(module)? {
1300-
Some(g) => g.color(args),
1301-
None => {
1302-
let mode = super::color::ColorMode::default();
1303-
super::color::extract_color_with_mode(args, &mode).map(super::color::PyColor::from)
1304-
}
1305-
}
1306-
}
1307-
13081312
#[pyfunction]
13091313
#[pyo3(pass_module, signature = (*args))]
13101314
fn background(module: &Bound<'_, PyModule>, args: &Bound<'_, PyTuple>) -> PyResult<()> {
@@ -1484,46 +1488,75 @@ mod mewnala {
14841488
graphics.create_image(width, height)
14851489
}
14861490

1491+
fn apply_light_transform(
1492+
light: &Light,
1493+
position: Option<super::math::Vec3Like>,
1494+
look_at: Option<super::math::Vec3Like>,
1495+
) -> PyResult<()> {
1496+
if let Some(p) = position {
1497+
::processing::prelude::transform_set_position(light.entity, p.into_vec3())
1498+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
1499+
}
1500+
if let Some(la) = look_at {
1501+
::processing::prelude::transform_look_at(light.entity, la.into_vec3())
1502+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
1503+
}
1504+
Ok(())
1505+
}
1506+
14871507
#[pyfunction]
1488-
#[pyo3(pass_module)]
1489-
fn create_directional_light(
1508+
#[pyo3(pass_module, signature = (color, illuminance, *, position=None, look_at=None))]
1509+
fn directional_light(
14901510
module: &Bound<'_, PyModule>,
14911511
color: super::color::ColorLike,
14921512
illuminance: f32,
1513+
position: Option<super::math::Vec3Like>,
1514+
look_at: Option<super::math::Vec3Like>,
14931515
) -> PyResult<Light> {
14941516
let graphics =
14951517
get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?;
1496-
graphics.light_directional(color, illuminance)
1518+
let light = graphics.light_directional(color, illuminance)?;
1519+
apply_light_transform(&light, position, look_at)?;
1520+
Ok(light)
14971521
}
14981522

14991523
#[pyfunction]
1500-
#[pyo3(pass_module)]
1501-
fn create_point_light(
1524+
#[pyo3(pass_module, signature = (color, intensity, range, radius, *, position=None, look_at=None))]
1525+
fn point_light(
15021526
module: &Bound<'_, PyModule>,
15031527
color: super::color::ColorLike,
15041528
intensity: f32,
15051529
range: f32,
15061530
radius: f32,
1531+
position: Option<super::math::Vec3Like>,
1532+
look_at: Option<super::math::Vec3Like>,
15071533
) -> PyResult<Light> {
15081534
let graphics =
15091535
get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?;
1510-
graphics.light_point(color, intensity, range, radius)
1536+
let light = graphics.light_point(color, intensity, range, radius)?;
1537+
apply_light_transform(&light, position, look_at)?;
1538+
Ok(light)
15111539
}
15121540

15131541
#[pyfunction]
1514-
#[pyo3(pass_module)]
1515-
fn create_spot_light(
1542+
#[pyo3(pass_module, signature = (color, intensity, range, radius, inner_angle, outer_angle, *, position=None, look_at=None))]
1543+
fn spot_light(
15161544
module: &Bound<'_, PyModule>,
15171545
color: super::color::ColorLike,
15181546
intensity: f32,
15191547
range: f32,
15201548
radius: f32,
15211549
inner_angle: f32,
15221550
outer_angle: f32,
1551+
position: Option<super::math::Vec3Like>,
1552+
look_at: Option<super::math::Vec3Like>,
15231553
) -> PyResult<Light> {
15241554
let graphics =
15251555
get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?;
1526-
graphics.light_spot(color, intensity, range, radius, inner_angle, outer_angle)
1556+
let light =
1557+
graphics.light_spot(color, intensity, range, radius, inner_angle, outer_angle)?;
1558+
apply_light_transform(&light, position, look_at)?;
1559+
Ok(light)
15271560
}
15281561

15291562
#[pyfunction(name = "sphere")]

crates/processing_pyo3/src/math.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,11 @@ macro_rules! impl_py_vec {
504504
}
505505

506506
impl_py_vec!(PyVec2, "Vec2", 2, [(x, set_x, 0), (y, set_y, 1)], Vec2, extra {
507+
#[classattr] #[allow(non_snake_case)] fn ZERO() -> Self { Self(Vec2::ZERO) }
508+
#[classattr] #[allow(non_snake_case)] fn ONE() -> Self { Self(Vec2::ONE) }
509+
#[classattr] #[allow(non_snake_case)] fn X() -> Self { Self(Vec2::X) }
510+
#[classattr] #[allow(non_snake_case)] fn Y() -> Self { Self(Vec2::Y) }
511+
507512
fn angle(&self) -> f32 {
508513
self.0.y.atan2(self.0.x)
509514
}
@@ -543,6 +548,12 @@ impl_py_vec!(PyVec2, "Vec2", 2, [(x, set_x, 0), (y, set_y, 1)], Vec2, extra {
543548
});
544549

545550
impl_py_vec!(PyVec3, "Vec3", 3, [(x, set_x, 0), (y, set_y, 1), (z, set_z, 2)], Vec3, extra {
551+
#[classattr] #[allow(non_snake_case)] fn ZERO() -> Self { Self(Vec3::ZERO) }
552+
#[classattr] #[allow(non_snake_case)] fn ONE() -> Self { Self(Vec3::ONE) }
553+
#[classattr] #[allow(non_snake_case)] fn X() -> Self { Self(Vec3::X) }
554+
#[classattr] #[allow(non_snake_case)] fn Y() -> Self { Self(Vec3::Y) }
555+
#[classattr] #[allow(non_snake_case)] fn Z() -> Self { Self(Vec3::Z) }
556+
546557
fn cross(&self, other: &Self) -> Self {
547558
Self(self.0.cross(other.0))
548559
}
@@ -570,6 +581,13 @@ impl_py_vec!(
570581
[(x, set_x, 0), (y, set_y, 1), (z, set_z, 2), (w, set_w, 3)],
571582
Vec4,
572583
extra {
584+
#[classattr] #[allow(non_snake_case)] fn ZERO() -> Self { Self(Vec4::ZERO) }
585+
#[classattr] #[allow(non_snake_case)] fn ONE() -> Self { Self(Vec4::ONE) }
586+
#[classattr] #[allow(non_snake_case)] fn X() -> Self { Self(Vec4::X) }
587+
#[classattr] #[allow(non_snake_case)] fn Y() -> Self { Self(Vec4::Y) }
588+
#[classattr] #[allow(non_snake_case)] fn Z() -> Self { Self(Vec4::Z) }
589+
#[classattr] #[allow(non_snake_case)] fn W() -> Self { Self(Vec4::W) }
590+
573591
fn truncate(&self) -> PyVec3 {
574592
PyVec3(self.0.truncate())
575593
}

crates/processing_render/src/graphics.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,12 @@ pub fn mode_3d(
303303
let fov = std::f32::consts::PI / 3.0; // 60 degrees
304304
let aspect = width / height;
305305
let camera_z = (height / 2.0) / (fov / 2.0).tan();
306-
let near = camera_z / 10.0;
306+
// Processing4 uses near = camera_z / 10, but that clips anything closer
307+
// than ~camera_z/10 to the camera. Since `transform_set_position` lets the
308+
// user move the camera without recomputing the projection, a small fixed
309+
// near is safer and matches most engines' defaults.
310+
let near = 1.0;
307311
let far = camera_z * 10.0;
308-
309-
// TODO: Setting this as a default, but we need to think about API around
310-
// a user defined value
311312
let near_clip_plane = vec4(0.0, 0.0, -1.0, -near);
312313

313314
let mut projection = projections

0 commit comments

Comments
 (0)