Skip to main content

pybevy_camera/
viewport.rs

1use bevy::camera::Viewport;
2use pybevy_core::{FromBorrowedStorage, field_storage::FieldStorage};
3use pybevy_macros::native_field;
4use pybevy_math::PyUVec2;
5use pyo3::{basic::CompareOp, exceptions::PyTypeError, prelude::*};
6
7#[native_field]
8#[pyclass(name = "Viewport")]
9#[derive(Debug)]
10pub struct PyViewport {
11    storage: FieldStorage<Viewport>,
12}
13
14#[pymethods]
15impl PyViewport {
16    #[new]
17    #[pyo3(signature = (physical_position = PyUVec2::ZERO, physical_size = PyUVec2::ONE, depth=(0.0, 1.0)))]
18    pub fn new(physical_position: PyUVec2, physical_size: PyUVec2, depth: (f32, f32)) -> Self {
19        Self::from_owned(Viewport {
20            physical_position: physical_position.into(),
21            physical_size: physical_size.into(),
22            depth: depth.0..depth.1,
23        })
24    }
25
26    #[getter]
27    pub fn physical_position(&self) -> PyResult<PyUVec2> {
28        Ok(self.storage.borrow_field_as(|v| &v.physical_position)?)
29    }
30
31    #[setter]
32    pub fn set_physical_position(&mut self, value: PyUVec2) -> PyResult<()> {
33        self.as_mut()?.physical_position = value.into();
34        Ok(())
35    }
36
37    #[getter]
38    pub fn physical_size(&self) -> PyResult<PyUVec2> {
39        Ok(self.storage.borrow_field_as(|v| &v.physical_size)?)
40    }
41
42    #[setter]
43    pub fn set_physical_size(&mut self, value: PyUVec2) -> PyResult<()> {
44        self.as_mut()?.physical_size = value.into();
45        Ok(())
46    }
47
48    #[getter]
49    pub fn depth(&self) -> PyResult<(f32, f32)> {
50        let viewport = self.as_ref()?;
51        Ok((viewport.depth.start, viewport.depth.end))
52    }
53
54    #[setter]
55    pub fn set_depth(&mut self, value: (f32, f32)) -> PyResult<()> {
56        self.as_mut()?.depth = value.0..value.1;
57        Ok(())
58    }
59
60    pub fn __repr__(&self) -> PyResult<String> {
61        let viewport = self.as_ref()?;
62        Ok(format!(
63            "Viewport(physical_position=UVec2({}, {}), physical_size=UVec2({}, {}), depth=({}, {}))",
64            viewport.physical_position.x,
65            viewport.physical_position.y,
66            viewport.physical_size.x,
67            viewport.physical_size.y,
68            viewport.depth.start,
69            viewport.depth.end
70        ))
71    }
72
73    pub fn __richcmp__(&self, other: &PyViewport, op: CompareOp) -> PyResult<bool> {
74        let self_viewport = self.as_ref()?;
75        let other_viewport = other.as_ref()?;
76        match op {
77            CompareOp::Eq => Ok(self_viewport.physical_position
78                == other_viewport.physical_position
79                && self_viewport.physical_size == other_viewport.physical_size
80                && self_viewport.depth == other_viewport.depth),
81            CompareOp::Ne => Ok(self_viewport.physical_position
82                != other_viewport.physical_position
83                || self_viewport.physical_size != other_viewport.physical_size
84                || self_viewport.depth != other_viewport.depth),
85            _ => Err(PyTypeError::new_err("Unsupported comparison operation")),
86        }
87    }
88
89    pub fn __copy__(&self) -> PyResult<Self> {
90        Ok(Self::from_owned(self.storage.get()?))
91    }
92
93    pub fn clamp_to_size(&mut self, size: PyUVec2) -> PyResult<()> {
94        self.as_mut()?.clamp_to_size(size.into());
95        Ok(())
96    }
97
98    #[staticmethod]
99    pub fn from_viewport_and_override(
100        viewport: Option<&PyViewport>,
101        main_pass_resolution_override: Option<PyUVec2>,
102    ) -> PyResult<Option<PyViewport>> {
103        let mut result_viewport = viewport.map(|v| v.storage.get()).transpose()?;
104
105        if let Some(override_size) = main_pass_resolution_override {
106            if result_viewport.is_none() {
107                result_viewport = Some(Viewport::default());
108            }
109            if let Some(ref mut vp) = result_viewport {
110                vp.physical_size = override_size.into();
111            }
112        }
113
114        Ok(result_viewport.map(PyViewport::from_owned))
115    }
116}