Skip to content

Commit 70cab45

Browse files
authored
Geometry Functions (#55)
1 parent f967a3e commit 70cab45

File tree

4 files changed

+231
-2
lines changed

4 files changed

+231
-2
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from processing import *
2+
from math import sin, cos
3+
4+
geometry = None
5+
grid_size = 20
6+
spacing = 10.0
7+
offset = (grid_size * spacing) / 2.0;
8+
time = 0.0
9+
10+
def setup():
11+
global geometry
12+
size(800, 600)
13+
mode_3d()
14+
geometry = Geometry()
15+
for z in range(grid_size):
16+
for x in range(grid_size):
17+
px = x * spacing - offset
18+
pz = z * spacing - offset
19+
geometry.color(x/grid_size, 0.5, z/grid_size, 1.0)
20+
geometry.normal(0.0, 1.0, 0.0)
21+
geometry.vertex(px, 0.0, pz)
22+
23+
for z in range(grid_size-1):
24+
for x in range(grid_size-1):
25+
tl = z * grid_size + x
26+
tr = tl + 1
27+
bl = (z + 1) * grid_size + x
28+
br = bl + 1
29+
30+
geometry.index(tl)
31+
geometry.index(bl)
32+
geometry.index(tr)
33+
34+
geometry.index(tr)
35+
geometry.index(bl)
36+
geometry.index(br)
37+
38+
39+
def draw():
40+
global geometry
41+
global grid_size
42+
global offset
43+
global spacing
44+
global time
45+
46+
camera_position(150.0, 150.0, 150.0)
47+
camera_look_at( 0.0, 0.0, 0.0)
48+
background(220, 200, 140)
49+
50+
for z in range(grid_size):
51+
for x in range(grid_size):
52+
idx = int(z * grid_size + x)
53+
px = x * spacing - offset
54+
pz = z * spacing - offset
55+
wave = sin(px * 0.1 + time) * cos(pz * 0.1 + time) * 20.0
56+
geometry.set_vertex(idx, px, wave, pz)
57+
58+
draw_geometry(geometry)
59+
60+
time += 0.05
61+
62+
63+
# TODO: this should happen implicitly on module load somehow
64+
run()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from processing import *
2+
3+
angle = 0.0
4+
5+
def setup():
6+
size(800, 600)
7+
mode_3d()
8+
9+
def draw():
10+
global angle
11+
camera_position(100.0, 100.0, 300.0)
12+
camera_look_at(0.0, 0.0, 0.0)
13+
background(220)
14+
15+
push_matrix()
16+
rotate(angle)
17+
draw_box(100.0, 100.0, 100.0)
18+
pop_matrix()
19+
20+
angle += 0.02
21+
22+
23+
# TODO: this should happen implicitly on module load somehow
24+
run()
25+

crates/processing_pyo3/src/graphics.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bevy::prelude::Entity;
22
use processing::prelude::*;
3-
use pyo3::{exceptions::PyRuntimeError, prelude::*};
3+
use pyo3::{exceptions::PyRuntimeError, prelude::*, types::PyDict};
44

55
use crate::glfw::GlfwContext;
66

@@ -35,6 +35,71 @@ impl Drop for Image {
3535
}
3636
}
3737

38+
#[pyclass(unsendable)]
39+
pub struct Geometry {
40+
entity: Entity,
41+
}
42+
43+
#[pyclass]
44+
pub enum Topology {
45+
PointList = 0,
46+
LineList = 1,
47+
LineStrip = 2,
48+
TriangleList = 3,
49+
TriangleStrip = 4,
50+
}
51+
52+
impl Topology {
53+
pub fn as_u8(&self) -> u8 {
54+
match self {
55+
Self::PointList => 0,
56+
Self::LineList => 1,
57+
Self::LineStrip => 2,
58+
Self::TriangleList => 3,
59+
Self::TriangleStrip => 4,
60+
}
61+
}
62+
}
63+
64+
#[pymethods]
65+
impl Geometry {
66+
#[new]
67+
#[pyo3(signature = (**kwargs))]
68+
pub fn new(kwargs: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
69+
let topology = kwargs
70+
.and_then(|k| k.get_item("topology").ok().flatten())
71+
.and_then(|t| t.cast_into::<Topology>().ok())
72+
.and_then(|t| geometry::Topology::from_u8(t.borrow().as_u8()))
73+
.unwrap_or(geometry::Topology::TriangleList);
74+
75+
let geometry =
76+
geometry_create(topology).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
77+
Ok(Self { entity: geometry })
78+
}
79+
80+
pub fn color(&self, r: f32, g: f32, b: f32, a: f32) -> PyResult<()> {
81+
geometry_color(self.entity, r, g, b, a).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
82+
}
83+
84+
pub fn normal(&self, nx: f32, ny: f32, nz: f32) -> PyResult<()> {
85+
geometry_normal(self.entity, nx, ny, nz)
86+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
87+
}
88+
89+
pub fn vertex(&self, x: f32, y: f32, z: f32) -> PyResult<()> {
90+
geometry_vertex(self.entity, x, y, z).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
91+
}
92+
93+
pub fn index(&self, i: u32) -> PyResult<()> {
94+
geometry_index(self.entity, i).map_err(|e| PyRuntimeError::new_err(format!("{e}")))
95+
}
96+
97+
pub fn set_vertex(&self, i: u32, x: f32, y: f32, z: f32) -> PyResult<()> {
98+
geometry_set_vertex(self.entity, i, x, y, z)
99+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
100+
}
101+
}
102+
38103
#[pyclass(unsendable)]
39104
pub struct Graphics {
40105
entity: Entity,
@@ -173,6 +238,17 @@ impl Graphics {
173238
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
174239
}
175240

241+
pub fn draw_box(&self, x: f32, y: f32, z: f32) -> PyResult<()> {
242+
let box_geo = geometry_box(x, y, z).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
243+
graphics_record_command(self.entity, DrawCommand::Geometry(box_geo))
244+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
245+
}
246+
247+
pub fn draw_geometry(&self, geometry: &Geometry) -> PyResult<()> {
248+
graphics_record_command(self.entity, DrawCommand::Geometry(geometry.entity))
249+
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
250+
}
251+
176252
pub fn scale(&self, x: f32, y: f32) -> PyResult<()> {
177253
graphics_record_command(self.entity, DrawCommand::Scale { x, y })
178254
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))

crates/processing_pyo3/src/lib.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
mod glfw;
1212
mod graphics;
1313

14-
use graphics::{Graphics, Image, get_graphics, get_graphics_mut};
14+
use graphics::{Geometry, Graphics, Image, Topology, get_graphics, get_graphics_mut};
1515
use pyo3::{exceptions::PyRuntimeError, prelude::*, types::PyTuple};
1616

1717
use std::env;
@@ -20,8 +20,17 @@ use std::env;
2020
fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
2121
m.add_class::<Graphics>()?;
2222
m.add_class::<Image>()?;
23+
m.add_class::<Geometry>()?;
24+
m.add_class::<Topology>()?;
2325
m.add_function(wrap_pyfunction!(size, m)?)?;
2426
m.add_function(wrap_pyfunction!(run, m)?)?;
27+
m.add_function(wrap_pyfunction!(mode_3d, m)?)?;
28+
m.add_function(wrap_pyfunction!(camera_position, m)?)?;
29+
m.add_function(wrap_pyfunction!(camera_look_at, m)?)?;
30+
m.add_function(wrap_pyfunction!(push_matrix, m)?)?;
31+
m.add_function(wrap_pyfunction!(pop_matrix, m)?)?;
32+
m.add_function(wrap_pyfunction!(rotate, m)?)?;
33+
m.add_function(wrap_pyfunction!(draw_box, m)?)?;
2534
m.add_function(wrap_pyfunction!(background, m)?)?;
2635
m.add_function(wrap_pyfunction!(fill, m)?)?;
2736
m.add_function(wrap_pyfunction!(no_fill, m)?)?;
@@ -30,6 +39,8 @@ fn processing(m: &Bound<'_, PyModule>) -> PyResult<()> {
3039
m.add_function(wrap_pyfunction!(stroke_weight, m)?)?;
3140
m.add_function(wrap_pyfunction!(rect, m)?)?;
3241
m.add_function(wrap_pyfunction!(image, m)?)?;
42+
m.add_function(wrap_pyfunction!(draw_geometry, m)?)?;
43+
3344
Ok(())
3445
}
3546

@@ -97,6 +108,59 @@ fn run(module: &Bound<'_, PyModule>) -> PyResult<()> {
97108
})
98109
}
99110

111+
#[pyfunction]
112+
#[pyo3(pass_module)]
113+
fn mode_3d(module: &Bound<'_, PyModule>) -> PyResult<()> {
114+
get_graphics(module)?.mode_3d()
115+
}
116+
117+
#[pyfunction]
118+
#[pyo3(pass_module)]
119+
fn camera_position(module: &Bound<'_, PyModule>, x: f32, y: f32, z: f32) -> PyResult<()> {
120+
get_graphics(module)?.camera_position(x, y, z)
121+
}
122+
123+
#[pyfunction]
124+
#[pyo3(pass_module)]
125+
fn camera_look_at(
126+
module: &Bound<'_, PyModule>,
127+
target_x: f32,
128+
target_y: f32,
129+
target_z: f32,
130+
) -> PyResult<()> {
131+
get_graphics(module)?.camera_look_at(target_x, target_y, target_z)
132+
}
133+
134+
#[pyfunction]
135+
#[pyo3(pass_module)]
136+
fn push_matrix(module: &Bound<'_, PyModule>) -> PyResult<()> {
137+
get_graphics(module)?.push_matrix()
138+
}
139+
140+
#[pyfunction]
141+
#[pyo3(pass_module)]
142+
fn pop_matrix(module: &Bound<'_, PyModule>) -> PyResult<()> {
143+
get_graphics(module)?.push_matrix()
144+
}
145+
146+
#[pyfunction]
147+
#[pyo3(pass_module)]
148+
fn rotate(module: &Bound<'_, PyModule>, angle: f32) -> PyResult<()> {
149+
get_graphics(module)?.rotate(angle)
150+
}
151+
152+
#[pyfunction]
153+
#[pyo3(pass_module)]
154+
fn draw_box(module: &Bound<'_, PyModule>, x: f32, y: f32, z: f32) -> PyResult<()> {
155+
get_graphics(module)?.draw_box(x, y, z)
156+
}
157+
158+
#[pyfunction]
159+
#[pyo3(pass_module, signature = (geometry))]
160+
fn draw_geometry(module: &Bound<'_, PyModule>, geometry: &Bound<'_, Geometry>) -> PyResult<()> {
161+
get_graphics(module)?.draw_geometry(&*geometry.extract::<PyRef<Geometry>>()?)
162+
}
163+
100164
#[pyfunction]
101165
#[pyo3(pass_module, signature = (*args))]
102166
fn background(module: &Bound<'_, PyModule>, args: &Bound<'_, PyTuple>) -> PyResult<()> {

0 commit comments

Comments
 (0)