Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"crates/wgsparkl-testbed3d",
"crates/wgsparkl2d",
"crates/wgsparkl3d",
"crates/text_to_collider",
"examples3d",
"examples2d",
]
Expand Down
18 changes: 18 additions & 0 deletions crates/text_to_collider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "text_to_collider"
version = "0.1.0"
license = "Apache-2.0 OR Custom"
edition = "2021"

[lints]
workspace = true

[dependencies]
env_logger = "*"
cosmic-text = "*"
image = "*"
parry3d = "*"
rkyv = { version = "0.8" }

[dev-dependencies]
bevy = "0.15"
33 changes: 33 additions & 0 deletions crates/text_to_collider/examples/color_positions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::fs;

use bevy::math::Vec2;
use cosmic_text::Color;
use parry3d::{na::Vector2, shape::Cuboid};
use text_to_collider::{get_rects_for, Rect, HEIGHT, WIDTH};

fn main() {
let rects = get_rects_for("Wgsparkl 🌊✨");
let positions = std::fs::read("particles.bin")
.expect("Could not read particles.bin, generate it by running example sand3.");
let positions = rkyv::from_bytes::<Vec<[f32; 3]>, rkyv::rancor::Error>(&positions).unwrap();
let detection_radius = 2f32;
let colors = positions
.iter()
.map(|p| {
// dismiss the y coordinate
let pos_to_check =
Vec2::new(p[0], -p[2] + 20f32) * 8f32 + Vec2::new(WIDTH, 0f32) / 2f32;
if let Some(c) = rects.iter().find(|c| {
let c1 = Vec2::new(c.x as f32, c.y as f32);
c1.distance_squared(pos_to_check) < detection_radius
}) {
let color = c.color.as_rgba();
[color[0], color[1], color[2]]
} else {
[0, 55, 200]
}
})
.collect::<Vec<_>>();
let particle_bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&colors).unwrap();
std::fs::write("particles_colors.bin", &particle_bytes).unwrap();
}
75 changes: 75 additions & 0 deletions crates/text_to_collider/examples/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use bevy::{input::common_conditions::input_toggle_active, prelude::*};
use cosmic_text::Color;
use parry3d::{
bounding_volume::BoundingVolume,
math::Point,
na::{Isometry3, Point2, SVector, UnitQuaternion, Vector2},
query::PointQuery,
shape::{Ball, Cuboid},
};
use text_to_collider::{get_rects_for, Rect};

fn main() {
let rects = get_rects_for("Wgsparkl 🌊✨");

App::new()
.add_plugins(DefaultPlugins)
.insert_resource(Cuboids(rects.iter().map(|r| r.to_cuboid(2f32)).collect()))
.insert_resource(RectsStorage(rects))
.add_systems(Startup, setup)
.add_systems(
Update,
show_rects.run_if(input_toggle_active(true, KeyCode::Space)),
)
.add_systems(Update, show_cuboids)
.run();
}

#[derive(Resource)]
pub struct RectsStorage(pub Vec<Rect>);

#[derive(Resource)]
pub struct Cuboids(pub Vec<(Cuboid, Vector2<f32>, Color)>);

pub fn setup(mut commands: Commands) {
commands.spawn((Camera::default(), Camera2d));
}

pub fn show_rects(mut g: Gizmos, rects: Res<RectsStorage>) {
for r in rects.0.iter() {
let color = r.color.as_rgba();
g.rect(
Isometry3d::from_translation(Vec3::new(r.x as f32, r.y as f32, 0f32)),
Vec2::new(r.width as f32, r.height as f32),
bevy::prelude::Color::srgba_u8(color[0], color[1], color[2], color[3]),
);
}
}

pub fn show_cuboids(time: Res<Time>, mut g: Gizmos, cuboids: Res<Cuboids>) {
let detection_radius = 1f32;
for i in 0..8000 {
let t = ((time.elapsed_secs()) + i as f32 * 10.5) * 0.1f32;
let pos_to_check = Vec2::new(
(((t * (0.5 + (i + 1) as f32 / 5000f32) * 0.7f32).cos() + 1f32) / 2f32) * 500f32,
(((t * (0.5 + (i + 1) as f32 / 5000f32) * 0.71f32).cos() + 1f32) / 2f32) * -84f32,
);
if let Some(c) = cuboids.0.iter().find(|c| {
let c1 = Vec2::new(c.1.x, c.1.y);
c1.distance_squared(pos_to_check) < detection_radius
}) {
let color = c.2.as_rgba();
g.sphere(
Isometry3d::from_translation(pos_to_check.extend(0f32)),
detection_radius,
bevy::prelude::Color::srgba_u8(color[0], color[1], color[2], color[3]),
);
} else {
g.sphere(
Isometry3d::from_translation(pos_to_check.extend(0f32)),
detection_radius,
bevy::prelude::Color::srgba_u8(200, 0, 0, 255),
);
}
}
}
94 changes: 94 additions & 0 deletions crates/text_to_collider/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use cosmic_text::{
Attrs, Buffer, Color, Edit, Editor, Family, FontSystem, Metrics, Shaping, SwashCache,
};
use parry3d::{
na::{Vector2, Vector3},
shape::Cuboid,
};

pub const WIDTH: f32 = 523f32;
pub const HEIGHT: f32 = 256f32;

pub fn get_rects_for(string: &str) -> Vec<Rect> {
let mut font_system = FontSystem::new();
let mut swash_cache = SwashCache::new();

let metrics = Metrics::new(32.0, 44.0);
let mut editor = Editor::new(Buffer::new_empty(metrics.scale(1f32)));
let mut editor = editor.borrow_with(&mut font_system);

editor.with_buffer_mut(|buffer| {
buffer.set_size(Some(WIDTH), Some(HEIGHT));
let attrs = Attrs::new();
let comic_attrs = attrs.family(Family::Name("Comic Neue"));

let spans: &[(&str, Attrs)] =
&[(string, comic_attrs.metrics(Metrics::relative(64.0, 1.2)))];

buffer.set_rich_text(spans.iter().copied(), comic_attrs, Shaping::Advanced);
});

editor.shape_as_needed(true);

let font_color = Color::rgb(0xFF, 0xFF, 0xFF);
let cursor_color = Color(0);
let selection_color = Color::rgba(0xFF, 0xFF, 0xFF, 0x33);
let selected_text_color = Color::rgb(0xA0, 0xA0, 0xFF);
let mut rects = Vec::new();
editor.draw(
&mut swash_cache,
font_color,
cursor_color,
selection_color,
selected_text_color,
|x, y, lw, lh, color| {
if color.a() == 0 {
return;
}
rects.push(Rect {
x,
// invert y for bevy.
y: -y,
width: lw,
height: lh,
color,
})
},
);
rects
}

#[derive(Debug)]
pub struct Rect {
/// Left of the rect
pub x: i32,
/// Top of the rect
pub y: i32,
/// Width of the rect
pub width: u32,
/// Height of the rect
pub height: u32,
/// Color of the rect
pub color: Color,
}

impl Rect {
pub fn get_center(&self) -> (f32, f32) {
(
self.x as f32 - self.width as f32 / 2f32,
self.y as f32 + self.height as f32 / 2f32,
)
}
pub fn to_cuboid(&self, half_extent_z: f32) -> (Cuboid, Vector2<f32>, Color) {
let center = self.get_center();
return (
Cuboid::new(Vector3::new(
self.width as f32 / 2f32,
self.height as f32 / 2f32,
half_extent_z,
)),
Vector2::new(center.0, center.1),
self.color,
);
}
}
3 changes: 3 additions & 0 deletions examples3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ wgsparkl3d = { path = "../crates/wgsparkl3d", features = [
"load_bevy",
"load_obj",
] }
wgcore = "0.2"
obj-rs = { version = "0.7", default-features = false }
bevy_editor_cam = "*"
image = "0.25"
gltf = { version = "1.3", features = ["KHR_materials_pbrSpecularGlossiness"] }
rapier3d = "0.23"
futures = "0.3"
rkyv = "0.8"

[lints]
workspace = true
6 changes: 5 additions & 1 deletion examples3d/src/banana3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ pub fn demo(

fn move_knife_function(body_handle: RigidBodyHandle) -> Callback {
Box::new(
move |_render, physics: &mut PhysicsContext, _timestamps, app_state: &AppState| {
move |_render,
physics: &mut PhysicsContext,
_timestamps,
app_state: &AppState,
_render_queue| {
let t = app_state.physics_time_seconds as f32;

let body = physics.rapier_data.bodies.get_mut(body_handle).unwrap();
Expand Down
Loading