Skip to content

Commit f77cc47

Browse files
authored
Add camera functions (#47)
1 parent d4287e1 commit f77cc47

File tree

4 files changed

+368
-0
lines changed

4 files changed

+368
-0
lines changed

crates/processing_ffi/src/lib.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,64 @@ pub unsafe extern "C" fn processing_image_readback(
524524
Ok(())
525525
});
526526
}
527+
528+
#[unsafe(no_mangle)]
529+
pub extern "C" fn processing_mode_3d(window_id: u64) {
530+
error::clear_error();
531+
let window_entity = Entity::from_bits(window_id);
532+
error::check(|| graphics_mode_3d(window_entity));
533+
}
534+
535+
#[unsafe(no_mangle)]
536+
pub extern "C" fn processing_mode_2d(window_id: u64) {
537+
error::clear_error();
538+
let window_entity = Entity::from_bits(window_id);
539+
error::check(|| graphics_mode_2d(window_entity));
540+
}
541+
542+
#[unsafe(no_mangle)]
543+
pub extern "C" fn processing_camera_position(window_id: u64, x: f32, y: f32, z: f32) {
544+
error::clear_error();
545+
let window_entity = Entity::from_bits(window_id);
546+
error::check(|| graphics_camera_position(window_entity, x, y, z));
547+
}
548+
549+
#[unsafe(no_mangle)]
550+
pub extern "C" fn processing_camera_look_at(
551+
window_id: u64,
552+
target_x: f32,
553+
target_y: f32,
554+
target_z: f32,
555+
) {
556+
error::clear_error();
557+
let window_entity = Entity::from_bits(window_id);
558+
error::check(|| graphics_camera_look_at(window_entity, target_x, target_y, target_z));
559+
}
560+
561+
#[unsafe(no_mangle)]
562+
pub extern "C" fn processing_perspective(
563+
window_id: u64,
564+
fov: f32,
565+
aspect: f32,
566+
near: f32,
567+
far: f32,
568+
) {
569+
error::clear_error();
570+
let window_entity = Entity::from_bits(window_id);
571+
error::check(|| graphics_perspective(window_entity, fov, aspect, near, far));
572+
}
573+
574+
#[unsafe(no_mangle)]
575+
pub extern "C" fn processing_ortho(
576+
window_id: u64,
577+
left: f32,
578+
right: f32,
579+
bottom: f32,
580+
top: f32,
581+
near: f32,
582+
far: f32,
583+
) {
584+
error::clear_error();
585+
let window_entity = Entity::from_bits(window_id);
586+
error::check(|| graphics_ortho(window_entity, left, right, bottom, top, near, far));
587+
}

crates/processing_pyo3/src/graphics.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,43 @@ impl Graphics {
169169
pub fn end_draw(&self) -> PyResult<()> {
170170
graphics_end_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
171171
}
172+
173+
pub fn mode_3d(&self) -> PyResult<()> {
174+
graphics_mode_3d(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
175+
}
176+
177+
pub fn mode_2d(&self) -> PyResult<()> {
178+
graphics_mode_2d(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
179+
}
180+
181+
pub fn camera_position(&self, x: f32, y: f32, z: f32) -> PyResult<()> {
182+
graphics_camera_position(self.entity, x, y, z)
183+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
184+
}
185+
186+
pub fn camera_look_at(&self, target_x: f32, target_y: f32, target_z: f32) -> PyResult<()> {
187+
graphics_camera_look_at(self.entity, target_x, target_y, target_z)
188+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
189+
}
190+
191+
pub fn perspective(&self, fov: f32, aspect: f32, near: f32, far: f32) -> PyResult<()> {
192+
graphics_perspective(self.entity, fov, aspect, near, far)
193+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
194+
}
195+
196+
#[allow(clippy::too_many_arguments)]
197+
pub fn ortho(
198+
&self,
199+
left: f32,
200+
right: f32,
201+
bottom: f32,
202+
top: f32,
203+
near: f32,
204+
far: f32,
205+
) -> PyResult<()> {
206+
graphics_ortho(self.entity, left, right, bottom, top, near, far)
207+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
208+
}
172209
}
173210

174211
// TODO: a real color type. or color parser? idk. color is confusing. let's think

crates/processing_render/src/graphics.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,169 @@ pub fn resize(
275275
}
276276
}
277277

278+
pub fn mode_3d(
279+
In(entity): In<Entity>,
280+
mut projections: Query<&mut Projection>,
281+
mut transforms: Query<&mut Transform>,
282+
sizes: Query<&SurfaceSize>,
283+
) -> Result<()> {
284+
let SurfaceSize(width, height) = sizes
285+
.get(entity)
286+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
287+
288+
let width = *width as f32;
289+
let height = *height as f32;
290+
291+
let fov = std::f32::consts::PI / 3.0; // 60 degrees
292+
let aspect = width / height;
293+
let camera_z = (height / 2.0) / (fov / 2.0).tan();
294+
let near = camera_z / 10.0;
295+
let far = camera_z * 10.0;
296+
297+
let mut projection = projections
298+
.get_mut(entity)
299+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
300+
301+
*projection = Projection::Perspective(PerspectiveProjection {
302+
fov,
303+
aspect_ratio: aspect,
304+
near,
305+
far,
306+
});
307+
308+
let mut transform = transforms
309+
.get_mut(entity)
310+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
311+
312+
*transform = Transform::from_xyz(0.0, 0.0, camera_z).looking_at(Vec3::ZERO, Vec3::Y);
313+
314+
Ok(())
315+
}
316+
317+
pub fn mode_2d(
318+
In(entity): In<Entity>,
319+
mut projections: Query<&mut Projection>,
320+
mut transforms: Query<&mut Transform>,
321+
sizes: Query<&SurfaceSize>,
322+
) -> Result<()> {
323+
let SurfaceSize(width, height) = sizes
324+
.get(entity)
325+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
326+
327+
let mut projection = projections
328+
.get_mut(entity)
329+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
330+
331+
*projection = Projection::custom(ProcessingProjection {
332+
width: *width as f32,
333+
height: *height as f32,
334+
near: 0.0,
335+
far: 1000.0,
336+
});
337+
338+
let mut transform = transforms
339+
.get_mut(entity)
340+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
341+
342+
*transform = Transform::from_xyz(0.0, 0.0, 999.9);
343+
344+
Ok(())
345+
}
346+
347+
pub fn camera_position(
348+
In((entity, x, y, z)): In<(Entity, f32, f32, f32)>,
349+
mut transforms: Query<&mut Transform>,
350+
) -> Result<()> {
351+
let mut transform = transforms
352+
.get_mut(entity)
353+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
354+
355+
transform.translation = Vec3::new(x, y, z);
356+
357+
Ok(())
358+
}
359+
360+
pub fn camera_look_at(
361+
In((entity, target_x, target_y, target_z)): In<(Entity, f32, f32, f32)>,
362+
mut transforms: Query<&mut Transform>,
363+
) -> Result<()> {
364+
let mut transform = transforms
365+
.get_mut(entity)
366+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
367+
368+
// TODO: allow specifying up vector?
369+
// does anyone actually use anything other than Vec3::Y here?
370+
let target = Vec3::new(target_x, target_y, target_z);
371+
transform.look_at(target, Vec3::Y);
372+
373+
Ok(())
374+
}
375+
376+
pub fn perspective(
377+
In((
378+
entity,
379+
PerspectiveProjection {
380+
fov,
381+
aspect_ratio,
382+
near,
383+
far,
384+
},
385+
)): In<(Entity, PerspectiveProjection)>,
386+
mut projections: Query<&mut Projection>,
387+
) -> Result<()> {
388+
let mut projection = projections
389+
.get_mut(entity)
390+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
391+
392+
*projection = Projection::Perspective(PerspectiveProjection {
393+
fov,
394+
aspect_ratio,
395+
near,
396+
far,
397+
});
398+
399+
Ok(())
400+
}
401+
402+
pub struct OrthoArgs {
403+
pub left: f32,
404+
pub right: f32,
405+
pub bottom: f32,
406+
pub top: f32,
407+
pub near: f32,
408+
pub far: f32,
409+
}
410+
411+
pub fn ortho(
412+
In((
413+
entity,
414+
OrthoArgs {
415+
left,
416+
right,
417+
bottom,
418+
top,
419+
near,
420+
far,
421+
},
422+
)): In<(Entity, OrthoArgs)>,
423+
mut projections: Query<&mut Projection>,
424+
) -> Result<()> {
425+
let mut projection = projections
426+
.get_mut(entity)
427+
.map_err(|_| ProcessingError::GraphicsNotFound)?;
428+
429+
// we need a custom projection to support processing's coordinate system
430+
// but this is in effect an orthographic projection with the given bounds
431+
*projection = Projection::custom(ProcessingProjection {
432+
width: right - left,
433+
height: top - bottom,
434+
near,
435+
far,
436+
});
437+
438+
Ok(())
439+
}
440+
278441
pub fn destroy(
279442
In(entity): In<Entity>,
280443
mut commands: Commands,

crates/processing_render/src/lib.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use bevy::{
1717
use render::{activate_cameras, clear_transient_meshes, flush_draw_commands};
1818
use tracing::debug;
1919

20+
use crate::graphics::flush;
2021
use crate::{
2122
graphics::GraphicsPlugin, image::ImagePlugin, render::command::DrawCommand,
2223
surface::SurfacePlugin,
@@ -445,6 +446,112 @@ pub fn graphics_record_command(graphics_entity: Entity, cmd: DrawCommand) -> err
445446
})
446447
}
447448

449+
pub fn graphics_mode_3d(graphics_entity: Entity) -> error::Result<()> {
450+
app_mut(|app| {
451+
flush(app, graphics_entity)?;
452+
app.world_mut()
453+
.run_system_cached_with(graphics::mode_3d, graphics_entity)
454+
.unwrap()
455+
})
456+
}
457+
458+
pub fn graphics_mode_2d(graphics_entity: Entity) -> error::Result<()> {
459+
app_mut(|app| {
460+
flush(app, graphics_entity)?;
461+
app.world_mut()
462+
.run_system_cached_with(graphics::mode_2d, graphics_entity)
463+
.unwrap()
464+
})
465+
}
466+
467+
pub fn graphics_camera_position(
468+
graphics_entity: Entity,
469+
x: f32,
470+
y: f32,
471+
z: f32,
472+
) -> error::Result<()> {
473+
app_mut(|app| {
474+
flush(app, graphics_entity)?;
475+
app.world_mut()
476+
.run_system_cached_with(graphics::camera_position, (graphics_entity, x, y, z))
477+
.unwrap()
478+
})
479+
}
480+
481+
pub fn graphics_camera_look_at(
482+
graphics_entity: Entity,
483+
target_x: f32,
484+
target_y: f32,
485+
target_z: f32,
486+
) -> error::Result<()> {
487+
app_mut(|app| {
488+
flush(app, graphics_entity)?;
489+
app.world_mut()
490+
.run_system_cached_with(
491+
graphics::camera_look_at,
492+
(graphics_entity, target_x, target_y, target_z),
493+
)
494+
.unwrap()
495+
})
496+
}
497+
498+
pub fn graphics_perspective(
499+
graphics_entity: Entity,
500+
fov: f32,
501+
aspect_ratio: f32,
502+
near: f32,
503+
far: f32,
504+
) -> error::Result<()> {
505+
app_mut(|app| {
506+
flush(app, graphics_entity)?;
507+
app.world_mut()
508+
.run_system_cached_with(
509+
graphics::perspective,
510+
(
511+
graphics_entity,
512+
PerspectiveProjection {
513+
fov,
514+
aspect_ratio,
515+
near,
516+
far,
517+
},
518+
),
519+
)
520+
.unwrap()
521+
})
522+
}
523+
524+
#[allow(clippy::too_many_arguments)]
525+
pub fn graphics_ortho(
526+
graphics_entity: Entity,
527+
left: f32,
528+
right: f32,
529+
bottom: f32,
530+
top: f32,
531+
near: f32,
532+
far: f32,
533+
) -> error::Result<()> {
534+
app_mut(|app| {
535+
flush(app, graphics_entity)?;
536+
app.world_mut()
537+
.run_system_cached_with(
538+
graphics::ortho,
539+
(
540+
graphics_entity,
541+
graphics::OrthoArgs {
542+
left,
543+
right,
544+
bottom,
545+
top,
546+
near,
547+
far,
548+
},
549+
),
550+
)
551+
.unwrap()
552+
})
553+
}
554+
448555
/// Create a new image with given size and data.
449556
pub fn image_create(
450557
size: Extent3d,

0 commit comments

Comments
 (0)