Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ path = "examples/custom_attribute.rs"
name = "lights"
path = "examples/lights.rs"

[[example]]
name = "materials"
path = "examples/materials.rs"

[[example]]
name = "pbr"
path = "examples/pbr.rs"

[profile.wasm-release]
inherits = "release"
opt-level = "z"
Expand Down
67 changes: 67 additions & 0 deletions crates/processing_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,14 @@ pub extern "C" fn processing_geometry_box(width: f32, height: f32, depth: f32) -
.unwrap_or(0)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_geometry_sphere(radius: f32, sectors: u32, stacks: u32) -> u64 {
error::clear_error();
error::check(|| geometry_sphere(radius, sectors, stacks))
.map(|e| e.to_bits())
.unwrap_or(0)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_light_create_directional(
graphics_id: u64,
Expand Down Expand Up @@ -1146,3 +1154,62 @@ pub extern "C" fn processing_light_create_spot(
.map(|e| e.to_bits())
.unwrap_or(0)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_material_create_pbr() -> u64 {
error::clear_error();
error::check(|| material_create_pbr())
.map(|e| e.to_bits())
.unwrap_or(0)
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_material_set_float(
mat_id: u64,
name: *const std::ffi::c_char,
value: f32,
) {
error::clear_error();
let name = unsafe { std::ffi::CStr::from_ptr(name) }.to_str().unwrap();
error::check(|| {
material_set(
Entity::from_bits(mat_id),
name,
material::MaterialValue::Float(value),
)
});
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_material_set_float4(
mat_id: u64,
name: *const std::ffi::c_char,
r: f32,
g: f32,
b: f32,
a: f32,
) {
error::clear_error();
let name = unsafe { std::ffi::CStr::from_ptr(name) }.to_str().unwrap();
error::check(|| {
material_set(
Entity::from_bits(mat_id),
name,
material::MaterialValue::Float4([r, g, b, a]),
)
});
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_material_destroy(mat_id: u64) {
error::clear_error();
error::check(|| material_destroy(Entity::from_bits(mat_id)));
}

#[unsafe(no_mangle)]
pub extern "C" fn processing_material(window_id: u64, mat_id: u64) {
error::clear_error();
let window_entity = Entity::from_bits(window_id);
let mat_entity = Entity::from_bits(mat_id);
error::check(|| graphics_record_command(window_entity, DrawCommand::Material(mat_entity)));
}
27 changes: 27 additions & 0 deletions crates/processing_pyo3/examples/materials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from processing import *

mat = None

def setup():
global mat
size(800, 600)
mode_3d()

dir_light = create_directional_light(1.0, 0.98, 0.95, 1500.0)
point_light = create_point_light(1.0, 1.0, 1.0, 100000.0, 800.0, 0.0)
point_light.position(200.0, 200.0, 400.0)

mat = Material()
mat.set_float("roughness", 0.3)
mat.set_float("metallic", 0.8)
mat.set_float4("base_color", 1.0, 0.85, 0.57, 1.0)

def draw():
camera_position(0.0, 0.0, 200.0)
camera_look_at(0.0, 0.0, 0.0)
background(12, 12, 18)

use_material(mat)
draw_sphere(50.0)

run()
17 changes: 17 additions & 0 deletions crates/processing_pyo3/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,23 @@ impl Graphics {
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn draw_sphere(&self, radius: f32, sectors: u32, stacks: u32) -> PyResult<()> {
let sphere_geo = geometry_sphere(radius, sectors, stacks)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
graphics_record_command(self.entity, DrawCommand::Geometry(sphere_geo))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn draw_geometry(&self, geometry: &Geometry) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Geometry(geometry.entity))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn use_material(&self, material: &crate::material::Material) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn scale(&self, x: f32, y: f32) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Scale { x, y })
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
Expand All @@ -313,6 +325,11 @@ impl Graphics {
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn set_material(&self, material: &crate::material::Material) -> PyResult<()> {
graphics_record_command(self.entity, DrawCommand::Material(material.entity))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn begin_draw(&self) -> PyResult<()> {
graphics_begin_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}
Expand Down
22 changes: 22 additions & 0 deletions crates/processing_pyo3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
//! functions that forward to a singleton Graphics object pub(crate) behind the scenes.
mod glfw;
mod graphics;
pub(crate) mod material;

use graphics::{Geometry, Graphics, Image, Light, Topology, get_graphics, get_graphics_mut};
use material::Material;
use pyo3::{
exceptions::PyRuntimeError,
prelude::*,
Expand All @@ -27,6 +29,7 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Image>()?;
m.add_class::<Light>()?;
m.add_class::<Topology>()?;
m.add_class::<Material>()?;
m.add_function(wrap_pyfunction!(size, m)?)?;
m.add_function(wrap_pyfunction!(run, m)?)?;
m.add_function(wrap_pyfunction!(mode_3d, m)?)?;
Expand All @@ -48,6 +51,8 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(create_directional_light, m)?)?;
m.add_function(wrap_pyfunction!(create_point_light, m)?)?;
m.add_function(wrap_pyfunction!(create_spot_light, m)?)?;
m.add_function(wrap_pyfunction!(draw_sphere, m)?)?;
m.add_function(wrap_pyfunction!(use_material, m)?)?;

Ok(())
}
Expand Down Expand Up @@ -320,3 +325,20 @@ fn create_spot_light(
) -> PyResult<Light> {
get_graphics(module)?.light_spot(r, g, b, intensity, range, radius, inner_angle, outer_angle)
}

#[pyfunction]
#[pyo3(pass_module, signature = (radius, sectors=32, stacks=18))]
fn draw_sphere(
module: &Bound<'_, PyModule>,
radius: f32,
sectors: u32,
stacks: u32,
) -> PyResult<()> {
get_graphics(module)?.draw_sphere(radius, sectors, stacks)
}

#[pyfunction]
#[pyo3(pass_module, signature = (material))]
fn use_material(module: &Bound<'_, PyModule>, material: &Bound<'_, Material>) -> PyResult<()> {
get_graphics(module)?.use_material(&*material.extract::<PyRef<Material>>()?)
}
37 changes: 37 additions & 0 deletions crates/processing_pyo3/src/material.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use bevy::prelude::Entity;
use processing::prelude::*;
use pyo3::{exceptions::PyRuntimeError, prelude::*};

#[pyclass(unsendable)]
pub struct Material {
pub(crate) entity: Entity,
}

#[pymethods]
impl Material {
#[new]
pub fn new() -> PyResult<Self> {
let entity = material_create_pbr().map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
Ok(Self { entity })
}

pub fn set_float(&self, name: &str, value: f32) -> PyResult<()> {
material_set(self.entity, name, material::MaterialValue::Float(value))
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}

pub fn set_float4(&self, name: &str, r: f32, g: f32, b: f32, a: f32) -> PyResult<()> {
material_set(
self.entity,
name,
material::MaterialValue::Float4([r, g, b, a]),
)
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
}
}

impl Drop for Material {
fn drop(&mut self) {
let _ = material_destroy(self.entity);
}
}
4 changes: 4 additions & 0 deletions crates/processing_render/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ pub enum ProcessingError {
LayoutNotFound,
#[error("Transform not found")]
TransformNotFound,
#[error("Material not found")]
MaterialNotFound,
#[error("Unknown material property: {0}")]
UnknownMaterialProperty(String),
}
27 changes: 23 additions & 4 deletions crates/processing_render/src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use std::collections::HashMap;

use bevy::{
asset::RenderAssetUsages,
mesh::{Indices, MeshVertexAttributeId, Meshable, VertexAttributeValues},
mesh::{Indices, MeshVertexAttributeId, VertexAttributeValues},
prelude::*,
render::render_resource::PrimitiveTopology,
};

use crate::error::{ProcessingError, Result};
use crate::render::primitive::{box_mesh, sphere_mesh};

pub struct GeometryPlugin;

Expand Down Expand Up @@ -158,9 +159,27 @@ pub fn create_box(
mut meshes: ResMut<Assets<Mesh>>,
builtins: Res<BuiltinAttributes>,
) -> Entity {
let cuboid = Cuboid::new(width, height, depth);
let mesh = cuboid.mesh().build();
let handle = meshes.add(mesh);
let handle = meshes.add(box_mesh(width, height, depth));

let layout_entity = commands
.spawn(VertexLayout::with_attributes(vec![
builtins.position,
builtins.normal,
builtins.color,
builtins.uv,
]))
.id();

commands.spawn(Geometry::new(handle, layout_entity)).id()
}

pub fn create_sphere(
In((radius, sectors, stacks)): In<(f32, u32, u32)>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
builtins: Res<BuiltinAttributes>,
) -> Entity {
let handle = meshes.add(sphere_mesh(radius, sectors, stacks));

let layout_entity = commands
.spawn(VertexLayout::with_attributes(vec![
Expand Down
2 changes: 1 addition & 1 deletion crates/processing_render/src/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub fn create(
Transform::from_xyz(0.0, 0.0, 999.9),
render_layer,
CommandBuffer::new(),
RenderState::default(),
RenderState::new(),
SurfaceSize(width, height),
Graphics {
readback_buffer,
Expand Down
49 changes: 44 additions & 5 deletions crates/processing_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod geometry;
mod graphics;
pub mod image;
pub mod light;
pub mod material;
pub mod render;
pub mod sketch;
mod surface;
Expand All @@ -21,12 +22,12 @@ use bevy::{
prelude::*,
render::render_resource::{Extent3d, TextureFormat},
};
use render::material::add_standard_materials;
use render::{activate_cameras, clear_transient_meshes, flush_draw_commands};
use tracing::debug;

use crate::geometry::{AttributeFormat, AttributeValue};
use crate::graphics::flush;
use crate::render::material::add_standard_materials;
use crate::{
graphics::GraphicsPlugin, image::ImagePlugin, light::LightPlugin, render::command::DrawCommand,
surface::SurfacePlugin,
Expand Down Expand Up @@ -265,14 +266,14 @@ fn create_app(config: Config) -> App {
SurfacePlugin,
geometry::GeometryPlugin,
LightPlugin,
material::MaterialPlugin,
));
app.add_systems(First, (clear_transient_meshes, activate_cameras))
.add_systems(
Update,
(
flush_draw_commands.before(AssetEventSystems),
add_standard_materials.after(flush_draw_commands),
),
(flush_draw_commands, add_standard_materials)
.chain()
.before(AssetEventSystems),
);

app
Expand Down Expand Up @@ -1226,6 +1227,15 @@ pub fn geometry_box(width: f32, height: f32, depth: f32) -> error::Result<Entity
})
}

pub fn geometry_sphere(radius: f32, sectors: u32, stacks: u32) -> error::Result<Entity> {
app_mut(|app| {
Ok(app
.world_mut()
.run_system_cached_with(geometry::create_sphere, (radius, sectors, stacks))
.unwrap())
})
}

pub fn poll_for_sketch_updates() -> error::Result<Option<sketch::Sketch>> {
app_mut(|app| {
Ok(app
Expand All @@ -1234,3 +1244,32 @@ pub fn poll_for_sketch_updates() -> error::Result<Option<sketch::Sketch>> {
.unwrap())
})
}

pub fn material_create_pbr() -> error::Result<Entity> {
app_mut(|app| {
Ok(app
.world_mut()
.run_system_cached(material::create_pbr)
.unwrap())
})
}

pub fn material_set(
entity: Entity,
name: impl Into<String>,
value: material::MaterialValue,
) -> error::Result<()> {
app_mut(|app| {
app.world_mut()
.run_system_cached_with(material::set_property, (entity, name.into(), value))
.unwrap()
})
}

pub fn material_destroy(entity: Entity) -> error::Result<()> {
app_mut(|app| {
app.world_mut()
.run_system_cached_with(material::destroy, entity)
.unwrap()
})
}
Loading
Loading