Skip to main content

il2cpp_bridge_rs/structs/components/rendering/
camera.rs

1//! Unity Camera component wrapper
2use super::screen::Screen;
3use crate::api::cache;
4use crate::structs::collections::Il2cppArray;
5use crate::structs::components::{Component, ComponentTrait};
6use crate::structs::math::{Matrix4x4, Ray, Vector2, Vector3};
7use std::ffi::c_void;
8use std::ops::Deref;
9
10#[repr(i32)]
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum CameraEye {
13    Left = 0,
14    Right = 1,
15    Mono = 2,
16}
17
18#[repr(C)]
19#[derive(Debug, Clone, Copy)]
20pub struct Camera {
21    /// Base Component structure
22    pub component: Component,
23}
24
25impl ComponentTrait for Camera {
26    fn from_ptr(ptr: *mut c_void) -> Self {
27        Self {
28            component: Component::from_ptr(ptr),
29        }
30    }
31}
32
33impl Deref for Camera {
34    type Target = Component;
35    fn deref(&self) -> &Self::Target {
36        &self.component
37    }
38}
39
40impl Camera {
41    /// Gets the Camera class definition
42    ///
43    /// # Returns
44    /// * `Option<Class>` - The UnityEngine.Camera class
45    pub fn get_class() -> Option<crate::structs::core::Class> {
46        cache::coremodule().class("UnityEngine.Camera")
47    }
48
49    /// Gets the main camera in the scene (Camera.main)
50    ///
51    /// # Returns
52    /// * `Result<Option<Camera>, String>` - The main camera if it exists
53    pub fn get_main() -> Result<Option<Camera>, String> {
54        let class = Self::get_class().ok_or("Class 'UnityEngine.Camera' not found")?;
55        let method = class
56            .method("get_main")
57            .ok_or("Method 'get_main' not found")?;
58        unsafe {
59            let ptr = method.call::<*mut c_void>(&[])?;
60            if ptr.is_null() {
61                Ok(None)
62            } else {
63                Ok(Some(Camera::from_ptr(ptr)))
64            }
65        }
66    }
67
68    /// Gets the current camera (for rendering events)
69    ///
70    /// # Returns
71    /// * `Result<Option<Camera>, String>` - The current camera if it exists
72    pub fn get_current() -> Result<Option<Camera>, String> {
73        let class = Self::get_class().ok_or("Class 'UnityEngine.Camera' not found")?;
74        let method = class
75            .method("get_current")
76            .ok_or("Method 'get_current' not found")?;
77        unsafe {
78            let ptr = method.call::<*mut c_void>(&[])?;
79            if ptr.is_null() {
80                Ok(None)
81            } else {
82                Ok(Some(Camera::from_ptr(ptr)))
83            }
84        }
85    }
86
87    /// Gets the count of all active cameras
88    ///
89    /// # Returns
90    /// * `Result<i32, String>` - The number of all cameras enabled in the scene
91    pub fn get_all_count() -> Result<i32, String> {
92        let class = Self::get_class().ok_or("Class 'UnityEngine.Camera' not found")?;
93        let method = class
94            .method("get_allCamerasCount")
95            .ok_or("Method 'get_allCamerasCount' not found")?;
96        unsafe { method.call::<i32>(&[]) }
97    }
98
99    /// Gets a list of all active cameras
100    ///
101    /// # Returns
102    /// * `Result<Vec<Camera>, String>` - A vector containing all active cameras
103    pub fn get_all_cameras() -> Result<Vec<Camera>, String> {
104        let class = Self::get_class().ok_or("Class 'UnityEngine.Camera' not found")?;
105        let method = class
106            .method("GetAllCameras")
107            .ok_or("Method 'GetAllCameras' not found")?;
108
109        let count = Self::get_all_count()?;
110        if count == 0 {
111            return Ok(Vec::new());
112        }
113
114        let array_ptr = Il2cppArray::<*mut c_void>::new(&class, count as usize);
115        if array_ptr.is_null() {
116            return Err("Failed to create array".to_string());
117        }
118
119        unsafe {
120            method.call::<i32>(&[array_ptr as *mut c_void])?;
121
122            let array = &*array_ptr;
123            let mut cameras = Vec::with_capacity(count as usize);
124            for i in 0..count as usize {
125                let ptr = array.at(i);
126                if !ptr.is_null() {
127                    cameras.push(Camera::from_ptr(ptr));
128                }
129            }
130            Ok(cameras)
131        }
132    }
133
134    /// Gets the depth of the camera
135    ///
136    /// # Returns
137    /// * `Result<f32, String>` - The camera's depth in the rendering order
138    pub fn get_depth(&self) -> Result<f32, String> {
139        unsafe {
140            self.method("get_depth")
141                .ok_or("Method 'get_depth' not found")?
142                .call::<f32>(&[])
143        }
144    }
145
146    /// Sets the depth of the camera
147    ///
148    /// # Arguments
149    /// * `depth` - The new depth value
150    ///
151    /// # Returns
152    /// * `Result<(), String>` - Ok if success
153    pub fn set_depth(&self, depth: f32) -> Result<(), String> {
154        unsafe {
155            self.method("set_depth")
156                .ok_or("Method 'set_depth' not found")?
157                .call::<()>(&[&depth as *const f32 as *mut c_void])?;
158        }
159        Ok(())
160    }
161
162    /// Gets the field of view of the camera
163    ///
164    /// # Returns
165    /// * `Result<f32, String>` - The field of view in degrees
166    pub fn get_field_of_view(&self) -> Result<f32, String> {
167        unsafe {
168            self.method("get_fieldOfView")
169                .ok_or("Method 'get_fieldOfView' not found")?
170                .call::<f32>(&[])
171        }
172    }
173
174    /// Sets the field of view of the camera
175    ///
176    /// # Arguments
177    /// * `fov` - The new field of view in degrees
178    ///
179    /// # Returns
180    /// * `Result<(), String>` - Ok if success
181    pub fn set_field_of_view(&self, fov: f32) -> Result<(), String> {
182        unsafe {
183            self.method("set_fieldOfView")
184                .ok_or("Method 'set_fieldOfView' not found")?
185                .call::<()>(&[&fov as *const f32 as *mut c_void])?;
186        }
187        Ok(())
188    }
189
190    /// Converts a point from world space to screen space
191    ///
192    /// # Arguments
193    /// * `position` - The world position to convert
194    /// * `eye` - The camera eye to use for conversion
195    ///
196    /// # Returns
197    /// * `Result<Vector3, String>` - The screen point
198    pub fn world_to_screen_point(
199        &self,
200        position: Vector3,
201        eye: CameraEye,
202    ) -> Result<Vector3, String> {
203        unsafe {
204            self.method("WorldToScreenPoint")
205                .ok_or("Method 'WorldToScreenPoint' not found")?
206                .call::<Vector3>(&[
207                    &position as *const Vector3 as *mut c_void,
208                    &eye as *const CameraEye as *mut c_void,
209                ])
210        }
211    }
212
213    /// Converts a point from screen space to world space
214    ///
215    /// # Arguments
216    /// * `position` - The screen position to convert
217    /// * `eye` - The camera eye to use for conversion
218    ///
219    /// # Returns
220    /// * `Result<Vector3, String>` - The world point
221    pub fn screen_to_world_point(
222        &self,
223        position: Vector3,
224        eye: CameraEye,
225    ) -> Result<Vector3, String> {
226        unsafe {
227            self.method("ScreenToWorldPoint")
228                .ok_or("Method 'ScreenToWorldPoint' not found")?
229                .call::<Vector3>(&[
230                    &position as *const Vector3 as *mut c_void,
231                    &eye as *const CameraEye as *mut c_void,
232                ])
233        }
234    }
235
236    /// Gets the camera to world matrix
237    ///
238    /// # Returns
239    /// * `Result<Matrix4x4, String>` - The matrix that transforms from camera space to world space
240    pub fn camera_to_world_matrix(&self) -> Result<Matrix4x4, String> {
241        unsafe {
242            self.method("get_cameraToWorldMatrix")
243                .ok_or("Method 'get_cameraToWorldMatrix' not found")?
244                .call::<Matrix4x4>(&[])
245        }
246    }
247
248    /// Converts world position to screen coordinates and checks if it's on screen
249    ///
250    /// # Arguments
251    /// * `position` - The world position
252    /// * `eye` - The camera eye
253    ///
254    /// # Returns
255    /// * `Result<(Vector2, bool), String>` - A tuple of (screen position, is on screen)
256    pub fn world_to_screen(
257        &self,
258        position: Vector3,
259        eye: CameraEye,
260    ) -> Result<(Vector2, bool), String> {
261        let mut screen_point = self.world_to_screen_point(position, eye)?;
262
263        if screen_point.z < 0.01 {
264            return Ok((Vector2 { x: 0.0, y: 0.0 }, false));
265        }
266
267        let screen_width = Screen::get_width()? as f32;
268        let screen_height = Screen::get_height()? as f32;
269
270        screen_point.y = screen_height - screen_point.y;
271
272        let on_screen = screen_point.x > 0.0
273            && screen_point.x < screen_width
274            && screen_point.y > 0.0
275            && screen_point.y < screen_height;
276
277        Ok((
278            Vector2 {
279                x: screen_point.x,
280                y: screen_point.y,
281            },
282            on_screen,
283        ))
284    }
285
286    /// Returns a ray from the camera through a screen point
287    ///
288    /// # Arguments
289    /// * `position` - The screen position
290    /// * `eye` - The camera eye
291    ///
292    /// # Returns
293    /// * `Result<Ray, String>` - The ray passing through the screen point
294    pub fn screen_point_to_ray(&self, position: Vector2, eye: CameraEye) -> Result<Ray, String> {
295        unsafe {
296            self.method("ScreenPointToRay")
297                .ok_or("Method 'ScreenPointToRay' not found")?
298                .call::<Ray>(&[
299                    &position as *const Vector2 as *mut c_void,
300                    &eye as *const CameraEye as *mut c_void,
301                ])
302        }
303    }
304}