bevy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +4279 -0
- data/Cargo.toml +36 -0
- data/README.md +226 -0
- data/crates/bevy/Cargo.toml +52 -0
- data/crates/bevy/src/app.rs +43 -0
- data/crates/bevy/src/component.rs +111 -0
- data/crates/bevy/src/entity.rs +30 -0
- data/crates/bevy/src/error.rs +32 -0
- data/crates/bevy/src/event.rs +190 -0
- data/crates/bevy/src/input_bridge.rs +300 -0
- data/crates/bevy/src/lib.rs +42 -0
- data/crates/bevy/src/mesh_renderer.rs +328 -0
- data/crates/bevy/src/query.rs +53 -0
- data/crates/bevy/src/render_app.rs +689 -0
- data/crates/bevy/src/resource.rs +28 -0
- data/crates/bevy/src/schedule.rs +186 -0
- data/crates/bevy/src/sprite_renderer.rs +355 -0
- data/crates/bevy/src/system.rs +44 -0
- data/crates/bevy/src/text_renderer.rs +258 -0
- data/crates/bevy/src/types/color.rs +114 -0
- data/crates/bevy/src/types/dynamic.rs +131 -0
- data/crates/bevy/src/types/math.rs +260 -0
- data/crates/bevy/src/types/mod.rs +9 -0
- data/crates/bevy/src/types/transform.rs +166 -0
- data/crates/bevy/src/world.rs +163 -0
- data/crates/bevy_ruby_render/Cargo.toml +22 -0
- data/crates/bevy_ruby_render/src/asset.rs +360 -0
- data/crates/bevy_ruby_render/src/audio.rs +511 -0
- data/crates/bevy_ruby_render/src/camera.rs +365 -0
- data/crates/bevy_ruby_render/src/gamepad.rs +398 -0
- data/crates/bevy_ruby_render/src/lib.rs +26 -0
- data/crates/bevy_ruby_render/src/material.rs +310 -0
- data/crates/bevy_ruby_render/src/mesh.rs +491 -0
- data/crates/bevy_ruby_render/src/sprite.rs +289 -0
- data/ext/bevy/Cargo.toml +20 -0
- data/ext/bevy/extconf.rb +6 -0
- data/ext/bevy/src/conversions.rs +137 -0
- data/ext/bevy/src/lib.rs +29 -0
- data/ext/bevy/src/ruby_app.rs +65 -0
- data/ext/bevy/src/ruby_color.rs +149 -0
- data/ext/bevy/src/ruby_component.rs +189 -0
- data/ext/bevy/src/ruby_entity.rs +33 -0
- data/ext/bevy/src/ruby_math.rs +384 -0
- data/ext/bevy/src/ruby_query.rs +64 -0
- data/ext/bevy/src/ruby_render_app.rs +779 -0
- data/ext/bevy/src/ruby_system.rs +122 -0
- data/ext/bevy/src/ruby_world.rs +107 -0
- data/lib/bevy/animation.rb +597 -0
- data/lib/bevy/app.rb +675 -0
- data/lib/bevy/asset.rb +613 -0
- data/lib/bevy/audio.rb +545 -0
- data/lib/bevy/audio_effects.rb +224 -0
- data/lib/bevy/camera.rb +412 -0
- data/lib/bevy/component.rb +91 -0
- data/lib/bevy/diagnostics.rb +227 -0
- data/lib/bevy/ecs_advanced.rb +296 -0
- data/lib/bevy/event.rb +199 -0
- data/lib/bevy/gizmos.rb +158 -0
- data/lib/bevy/gltf.rb +227 -0
- data/lib/bevy/hierarchy.rb +444 -0
- data/lib/bevy/input.rb +514 -0
- data/lib/bevy/lighting.rb +369 -0
- data/lib/bevy/material.rb +248 -0
- data/lib/bevy/mesh.rb +257 -0
- data/lib/bevy/navigation.rb +344 -0
- data/lib/bevy/networking.rb +335 -0
- data/lib/bevy/particle.rb +337 -0
- data/lib/bevy/physics.rb +396 -0
- data/lib/bevy/plugins/default_plugins.rb +34 -0
- data/lib/bevy/plugins/input_plugin.rb +49 -0
- data/lib/bevy/reflect.rb +361 -0
- data/lib/bevy/render_graph.rb +210 -0
- data/lib/bevy/resource.rb +185 -0
- data/lib/bevy/scene.rb +254 -0
- data/lib/bevy/shader.rb +319 -0
- data/lib/bevy/shape.rb +195 -0
- data/lib/bevy/skeletal.rb +248 -0
- data/lib/bevy/sprite.rb +152 -0
- data/lib/bevy/sprite_sheet.rb +444 -0
- data/lib/bevy/state.rb +277 -0
- data/lib/bevy/system.rb +206 -0
- data/lib/bevy/text.rb +99 -0
- data/lib/bevy/text_advanced.rb +455 -0
- data/lib/bevy/timer.rb +147 -0
- data/lib/bevy/transform.rb +158 -0
- data/lib/bevy/ui.rb +454 -0
- data/lib/bevy/ui_advanced.rb +568 -0
- data/lib/bevy/version.rb +5 -0
- data/lib/bevy/visibility.rb +250 -0
- data/lib/bevy/window.rb +302 -0
- data/lib/bevy.rb +390 -0
- metadata +150 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
use bevy_color::Color;
|
|
2
|
+
use bevy_ecs::entity::Entity;
|
|
3
|
+
use bevy_ecs::world::World;
|
|
4
|
+
use bevy_math::Vec2;
|
|
5
|
+
use bevy_sprite::Sprite;
|
|
6
|
+
use bevy_transform::components::Transform;
|
|
7
|
+
use std::collections::HashMap;
|
|
8
|
+
|
|
9
|
+
#[derive(Debug, Clone)]
|
|
10
|
+
pub struct SpriteData {
|
|
11
|
+
pub color_r: f32,
|
|
12
|
+
pub color_g: f32,
|
|
13
|
+
pub color_b: f32,
|
|
14
|
+
pub color_a: f32,
|
|
15
|
+
pub flip_x: bool,
|
|
16
|
+
pub flip_y: bool,
|
|
17
|
+
pub anchor_x: f32,
|
|
18
|
+
pub anchor_y: f32,
|
|
19
|
+
pub has_custom_size: bool,
|
|
20
|
+
pub custom_size_x: f32,
|
|
21
|
+
pub custom_size_y: f32,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl Default for SpriteData {
|
|
25
|
+
fn default() -> Self {
|
|
26
|
+
Self {
|
|
27
|
+
color_r: 1.0,
|
|
28
|
+
color_g: 1.0,
|
|
29
|
+
color_b: 1.0,
|
|
30
|
+
color_a: 1.0,
|
|
31
|
+
flip_x: false,
|
|
32
|
+
flip_y: false,
|
|
33
|
+
anchor_x: 0.5,
|
|
34
|
+
anchor_y: 0.5,
|
|
35
|
+
has_custom_size: false,
|
|
36
|
+
custom_size_x: 0.0,
|
|
37
|
+
custom_size_y: 0.0,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl SpriteData {
|
|
43
|
+
pub fn new() -> Self {
|
|
44
|
+
Self::default()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn with_color(mut self, r: f32, g: f32, b: f32, a: f32) -> Self {
|
|
48
|
+
self.color_r = r;
|
|
49
|
+
self.color_g = g;
|
|
50
|
+
self.color_b = b;
|
|
51
|
+
self.color_a = a;
|
|
52
|
+
self
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn with_size(mut self, width: f32, height: f32) -> Self {
|
|
56
|
+
self.has_custom_size = true;
|
|
57
|
+
self.custom_size_x = width;
|
|
58
|
+
self.custom_size_y = height;
|
|
59
|
+
self
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn with_flip(mut self, flip_x: bool, flip_y: bool) -> Self {
|
|
63
|
+
self.flip_x = flip_x;
|
|
64
|
+
self.flip_y = flip_y;
|
|
65
|
+
self
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
pub fn to_bevy_color(&self) -> Color {
|
|
69
|
+
Color::srgba(self.color_r, self.color_g, self.color_b, self.color_a)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn custom_size(&self) -> Option<Vec2> {
|
|
73
|
+
if self.has_custom_size {
|
|
74
|
+
Some(Vec2::new(self.custom_size_x, self.custom_size_y))
|
|
75
|
+
} else {
|
|
76
|
+
None
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[derive(Debug, Clone)]
|
|
82
|
+
pub struct TransformData {
|
|
83
|
+
pub translation_x: f32,
|
|
84
|
+
pub translation_y: f32,
|
|
85
|
+
pub translation_z: f32,
|
|
86
|
+
pub rotation_x: f32,
|
|
87
|
+
pub rotation_y: f32,
|
|
88
|
+
pub rotation_z: f32,
|
|
89
|
+
pub rotation_w: f32,
|
|
90
|
+
pub scale_x: f32,
|
|
91
|
+
pub scale_y: f32,
|
|
92
|
+
pub scale_z: f32,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
impl Default for TransformData {
|
|
96
|
+
fn default() -> Self {
|
|
97
|
+
Self {
|
|
98
|
+
translation_x: 0.0,
|
|
99
|
+
translation_y: 0.0,
|
|
100
|
+
translation_z: 0.0,
|
|
101
|
+
rotation_x: 0.0,
|
|
102
|
+
rotation_y: 0.0,
|
|
103
|
+
rotation_z: 0.0,
|
|
104
|
+
rotation_w: 1.0,
|
|
105
|
+
scale_x: 1.0,
|
|
106
|
+
scale_y: 1.0,
|
|
107
|
+
scale_z: 1.0,
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
impl TransformData {
|
|
113
|
+
pub fn new() -> Self {
|
|
114
|
+
Self::default()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
|
|
118
|
+
Self {
|
|
119
|
+
translation_x: x,
|
|
120
|
+
translation_y: y,
|
|
121
|
+
translation_z: z,
|
|
122
|
+
..Default::default()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub fn to_bevy_transform(&self) -> Transform {
|
|
127
|
+
Transform {
|
|
128
|
+
translation: bevy_math::Vec3::new(
|
|
129
|
+
self.translation_x,
|
|
130
|
+
self.translation_y,
|
|
131
|
+
self.translation_z,
|
|
132
|
+
),
|
|
133
|
+
rotation: bevy_math::Quat::from_xyzw(
|
|
134
|
+
self.rotation_x,
|
|
135
|
+
self.rotation_y,
|
|
136
|
+
self.rotation_z,
|
|
137
|
+
self.rotation_w,
|
|
138
|
+
),
|
|
139
|
+
scale: bevy_math::Vec3::new(self.scale_x, self.scale_y, self.scale_z),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[derive(Debug, Clone)]
|
|
145
|
+
pub enum SpriteOperation {
|
|
146
|
+
Sync {
|
|
147
|
+
ruby_entity_id: u64,
|
|
148
|
+
sprite_data: SpriteData,
|
|
149
|
+
transform_data: TransformData,
|
|
150
|
+
},
|
|
151
|
+
Remove {
|
|
152
|
+
ruby_entity_id: u64,
|
|
153
|
+
},
|
|
154
|
+
Clear,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
struct EntityData {
|
|
158
|
+
bevy_entity: Entity,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
pub struct SpriteSync {
|
|
162
|
+
entity_map: HashMap<u64, EntityData>,
|
|
163
|
+
pub pending_operations: Vec<SpriteOperation>,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
impl SpriteSync {
|
|
167
|
+
pub fn new() -> Self {
|
|
168
|
+
Self {
|
|
169
|
+
entity_map: HashMap::new(),
|
|
170
|
+
pending_operations: Vec::new(),
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
pub fn sync_sprite_standalone(
|
|
175
|
+
&mut self,
|
|
176
|
+
ruby_entity_id: u64,
|
|
177
|
+
sprite_data: &SpriteData,
|
|
178
|
+
transform_data: &TransformData,
|
|
179
|
+
) {
|
|
180
|
+
self.pending_operations.push(SpriteOperation::Sync {
|
|
181
|
+
ruby_entity_id,
|
|
182
|
+
sprite_data: sprite_data.clone(),
|
|
183
|
+
transform_data: transform_data.clone(),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
pub fn remove_sprite_standalone(&mut self, ruby_entity_id: u64) {
|
|
188
|
+
self.pending_operations
|
|
189
|
+
.push(SpriteOperation::Remove { ruby_entity_id });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
pub fn clear_standalone(&mut self) {
|
|
193
|
+
self.pending_operations.push(SpriteOperation::Clear);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
pub fn apply_pending(&mut self, world: &mut World) {
|
|
197
|
+
let ops: Vec<_> = self.pending_operations.drain(..).collect();
|
|
198
|
+
for op in ops {
|
|
199
|
+
match op {
|
|
200
|
+
SpriteOperation::Sync {
|
|
201
|
+
ruby_entity_id,
|
|
202
|
+
sprite_data,
|
|
203
|
+
transform_data,
|
|
204
|
+
} => {
|
|
205
|
+
self.sync_sprite(world, ruby_entity_id, &sprite_data, &transform_data);
|
|
206
|
+
}
|
|
207
|
+
SpriteOperation::Remove { ruby_entity_id } => {
|
|
208
|
+
self.remove_sprite(world, ruby_entity_id);
|
|
209
|
+
}
|
|
210
|
+
SpriteOperation::Clear => {
|
|
211
|
+
self.clear(world);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
pub fn sync_sprite(
|
|
218
|
+
&mut self,
|
|
219
|
+
world: &mut World,
|
|
220
|
+
ruby_entity_id: u64,
|
|
221
|
+
sprite_data: &SpriteData,
|
|
222
|
+
transform_data: &TransformData,
|
|
223
|
+
) {
|
|
224
|
+
let color = sprite_data.to_bevy_color();
|
|
225
|
+
let custom_size = sprite_data.custom_size();
|
|
226
|
+
let transform = transform_data.to_bevy_transform();
|
|
227
|
+
|
|
228
|
+
if let Some(entity_data) = self.entity_map.get(&ruby_entity_id) {
|
|
229
|
+
let bevy_entity = entity_data.bevy_entity;
|
|
230
|
+
|
|
231
|
+
if let Some(mut sprite) = world.get_mut::<Sprite>(bevy_entity) {
|
|
232
|
+
sprite.color = color;
|
|
233
|
+
sprite.custom_size = custom_size;
|
|
234
|
+
sprite.flip_x = sprite_data.flip_x;
|
|
235
|
+
sprite.flip_y = sprite_data.flip_y;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if let Some(mut t) = world.get_mut::<Transform>(bevy_entity) {
|
|
239
|
+
*t = transform;
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
let bevy_entity = world
|
|
243
|
+
.spawn((
|
|
244
|
+
Sprite {
|
|
245
|
+
color,
|
|
246
|
+
custom_size,
|
|
247
|
+
flip_x: sprite_data.flip_x,
|
|
248
|
+
flip_y: sprite_data.flip_y,
|
|
249
|
+
..Default::default()
|
|
250
|
+
},
|
|
251
|
+
transform,
|
|
252
|
+
))
|
|
253
|
+
.id();
|
|
254
|
+
|
|
255
|
+
self.entity_map
|
|
256
|
+
.insert(ruby_entity_id, EntityData { bevy_entity });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
pub fn remove_sprite(&mut self, world: &mut World, ruby_entity_id: u64) {
|
|
261
|
+
if let Some(entity_data) = self.entity_map.remove(&ruby_entity_id) {
|
|
262
|
+
world.despawn(entity_data.bevy_entity);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
pub fn clear(&mut self, world: &mut World) {
|
|
267
|
+
for (_, entity_data) in self.entity_map.drain() {
|
|
268
|
+
world.despawn(entity_data.bevy_entity);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
pub fn len(&self) -> usize {
|
|
273
|
+
self.entity_map.len()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
pub fn is_empty(&self) -> bool {
|
|
277
|
+
self.entity_map.is_empty()
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
pub fn synced_entities(&self) -> Vec<u64> {
|
|
281
|
+
self.entity_map.keys().copied().collect()
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
impl Default for SpriteSync {
|
|
286
|
+
fn default() -> Self {
|
|
287
|
+
Self::new()
|
|
288
|
+
}
|
|
289
|
+
}
|
data/ext/bevy/Cargo.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "bevy"
|
|
3
|
+
version.workspace = true
|
|
4
|
+
edition.workspace = true
|
|
5
|
+
license.workspace = true
|
|
6
|
+
repository.workspace = true
|
|
7
|
+
publish = false
|
|
8
|
+
|
|
9
|
+
[lib]
|
|
10
|
+
crate-type = ["cdylib"]
|
|
11
|
+
|
|
12
|
+
[features]
|
|
13
|
+
default = ["rendering"]
|
|
14
|
+
rendering = ["bevy-ruby/rendering"]
|
|
15
|
+
|
|
16
|
+
[dependencies]
|
|
17
|
+
bevy-ruby = { path = "../../crates/bevy", default-features = false }
|
|
18
|
+
magnus.workspace = true
|
|
19
|
+
rb-sys = { workspace = true, features = ["stable-api-compiled-fallback"] }
|
|
20
|
+
parking_lot.workspace = true
|
data/ext/bevy/extconf.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
use bevy_ruby::types::{DynamicValue, RubyColor, RubyQuat, RubyTransform, RubyVec2, RubyVec3};
|
|
2
|
+
use magnus::{prelude::*, Error, RHash, Ruby, TryConvert, Value};
|
|
3
|
+
|
|
4
|
+
pub fn ruby_hash_to_dynamic_value(ruby: &Ruby, hash: &RHash) -> Result<std::collections::HashMap<String, DynamicValue>, Error> {
|
|
5
|
+
let mut result = std::collections::HashMap::new();
|
|
6
|
+
|
|
7
|
+
hash.foreach(|key: Value, value: Value| {
|
|
8
|
+
let key_str = String::try_convert(key)?;
|
|
9
|
+
let dynamic_value = value_to_dynamic(ruby, value)?;
|
|
10
|
+
result.insert(key_str, dynamic_value);
|
|
11
|
+
Ok(magnus::r_hash::ForEach::Continue)
|
|
12
|
+
})?;
|
|
13
|
+
|
|
14
|
+
Ok(result)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub fn value_to_dynamic(_ruby: &Ruby, value: Value) -> Result<DynamicValue, Error> {
|
|
18
|
+
if value.is_nil() {
|
|
19
|
+
return Ok(DynamicValue::Nil);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if let Ok(b) = bool::try_convert(value) {
|
|
23
|
+
return Ok(DynamicValue::Boolean(b));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if let Ok(i) = i64::try_convert(value) {
|
|
27
|
+
return Ok(DynamicValue::Integer(i));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if let Ok(f) = f64::try_convert(value) {
|
|
31
|
+
return Ok(DynamicValue::Float(f));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if let Ok(s) = String::try_convert(value) {
|
|
35
|
+
return Ok(DynamicValue::String(s));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Ok(DynamicValue::Nil)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn dynamic_to_value(ruby: &Ruby, value: &DynamicValue) -> Result<Value, Error> {
|
|
42
|
+
match value {
|
|
43
|
+
DynamicValue::Nil => Ok(ruby.qnil().as_value()),
|
|
44
|
+
DynamicValue::Boolean(b) => Ok(if *b { ruby.qtrue().as_value() } else { ruby.qfalse().as_value() }),
|
|
45
|
+
DynamicValue::Integer(i) => Ok(ruby.into_value(*i)),
|
|
46
|
+
DynamicValue::Float(f) => Ok(ruby.into_value(*f)),
|
|
47
|
+
DynamicValue::String(s) => Ok(ruby.into_value(s.clone())),
|
|
48
|
+
DynamicValue::Symbol(s) => Ok(ruby.into_value(s.clone())),
|
|
49
|
+
DynamicValue::Array(arr) => {
|
|
50
|
+
let array = ruby.ary_new_capa(arr.len());
|
|
51
|
+
for item in arr {
|
|
52
|
+
array.push(dynamic_to_value(ruby, item)?)?;
|
|
53
|
+
}
|
|
54
|
+
Ok(array.as_value())
|
|
55
|
+
}
|
|
56
|
+
DynamicValue::Hash(h) => {
|
|
57
|
+
let hash = ruby.hash_new();
|
|
58
|
+
for (k, v) in h {
|
|
59
|
+
hash.aset(k.clone(), dynamic_to_value(ruby, v)?)?;
|
|
60
|
+
}
|
|
61
|
+
Ok(hash.as_value())
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub fn vec2_from_hash(ruby: &Ruby, hash: &RHash) -> Result<RubyVec2, Error> {
|
|
67
|
+
let x: f64 = get_hash_value_or_default(ruby, hash, "x", 0.0)?;
|
|
68
|
+
let y: f64 = get_hash_value_or_default(ruby, hash, "y", 0.0)?;
|
|
69
|
+
Ok(RubyVec2::new(x as f32, y as f32))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn vec3_from_hash(ruby: &Ruby, hash: &RHash) -> Result<RubyVec3, Error> {
|
|
73
|
+
let x: f64 = get_hash_value_or_default(ruby, hash, "x", 0.0)?;
|
|
74
|
+
let y: f64 = get_hash_value_or_default(ruby, hash, "y", 0.0)?;
|
|
75
|
+
let z: f64 = get_hash_value_or_default(ruby, hash, "z", 0.0)?;
|
|
76
|
+
Ok(RubyVec3::new(x as f32, y as f32, z as f32))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub fn quat_from_hash(ruby: &Ruby, hash: &RHash) -> Result<RubyQuat, Error> {
|
|
80
|
+
let x: Option<f64> = get_hash_value(ruby, hash, "x")?;
|
|
81
|
+
let y: Option<f64> = get_hash_value(ruby, hash, "y")?;
|
|
82
|
+
let z: Option<f64> = get_hash_value(ruby, hash, "z")?;
|
|
83
|
+
|
|
84
|
+
if x.is_some() || y.is_some() || z.is_some() {
|
|
85
|
+
Ok(RubyQuat::from_euler(
|
|
86
|
+
x.unwrap_or(0.0) as f32,
|
|
87
|
+
y.unwrap_or(0.0) as f32,
|
|
88
|
+
z.unwrap_or(0.0) as f32,
|
|
89
|
+
))
|
|
90
|
+
} else {
|
|
91
|
+
Ok(RubyQuat::identity())
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pub fn color_from_hash(ruby: &Ruby, hash: &RHash) -> Result<RubyColor, Error> {
|
|
96
|
+
let r: f64 = get_hash_value_or_default(ruby, hash, "r", 1.0)?;
|
|
97
|
+
let g: f64 = get_hash_value_or_default(ruby, hash, "g", 1.0)?;
|
|
98
|
+
let b: f64 = get_hash_value_or_default(ruby, hash, "b", 1.0)?;
|
|
99
|
+
let a: f64 = get_hash_value_or_default(ruby, hash, "a", 1.0)?;
|
|
100
|
+
Ok(RubyColor::rgba(r as f32, g as f32, b as f32, a as f32))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pub fn transform_from_hash(ruby: &Ruby, hash: &RHash) -> Result<RubyTransform, Error> {
|
|
104
|
+
let tx: f64 = get_hash_value_or_default(ruby, hash, "x", 0.0)?;
|
|
105
|
+
let ty: f64 = get_hash_value_or_default(ruby, hash, "y", 0.0)?;
|
|
106
|
+
let tz: f64 = get_hash_value_or_default(ruby, hash, "z", 0.0)?;
|
|
107
|
+
|
|
108
|
+
let translation = RubyVec3::new(tx as f32, ty as f32, tz as f32);
|
|
109
|
+
|
|
110
|
+
let rotation: f64 = get_hash_value_or_default(ruby, hash, "rotation", 0.0)?;
|
|
111
|
+
let quat = RubyQuat::from_rotation_z(rotation as f32);
|
|
112
|
+
|
|
113
|
+
let sx: f64 = get_hash_value_or_default(ruby, hash, "scale_x", 1.0)?;
|
|
114
|
+
let sy: f64 = get_hash_value_or_default(ruby, hash, "scale_y", 1.0)?;
|
|
115
|
+
let sz: f64 = get_hash_value_or_default(ruby, hash, "scale_z", 1.0)?;
|
|
116
|
+
let scale = RubyVec3::new(sx as f32, sy as f32, sz as f32);
|
|
117
|
+
|
|
118
|
+
Ok(RubyTransform::from_translation_rotation_scale(translation, quat, scale))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fn get_hash_value<T: TryConvert>(ruby: &Ruby, hash: &RHash, key: &str) -> Result<Option<T>, Error> {
|
|
122
|
+
let sym = ruby.to_symbol(key);
|
|
123
|
+
match hash.get(sym) {
|
|
124
|
+
Some(val) => {
|
|
125
|
+
if val.is_nil() {
|
|
126
|
+
Ok(None)
|
|
127
|
+
} else {
|
|
128
|
+
Ok(Some(TryConvert::try_convert(val)?))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
None => Ok(None),
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fn get_hash_value_or_default<T: TryConvert>(ruby: &Ruby, hash: &RHash, key: &str, default: T) -> Result<T, Error> {
|
|
136
|
+
get_hash_value(ruby, hash, key).map(|opt| opt.unwrap_or(default))
|
|
137
|
+
}
|
data/ext/bevy/src/lib.rs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
mod conversions;
|
|
2
|
+
mod ruby_app;
|
|
3
|
+
mod ruby_color;
|
|
4
|
+
mod ruby_component;
|
|
5
|
+
mod ruby_entity;
|
|
6
|
+
mod ruby_math;
|
|
7
|
+
mod ruby_query;
|
|
8
|
+
mod ruby_render_app;
|
|
9
|
+
mod ruby_system;
|
|
10
|
+
mod ruby_world;
|
|
11
|
+
|
|
12
|
+
use magnus::{Error, Ruby};
|
|
13
|
+
|
|
14
|
+
#[magnus::init]
|
|
15
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
16
|
+
let module = ruby.define_module("Bevy")?;
|
|
17
|
+
|
|
18
|
+
ruby_app::define(ruby, &module)?;
|
|
19
|
+
ruby_color::define(ruby, &module)?;
|
|
20
|
+
ruby_component::define(ruby, &module)?;
|
|
21
|
+
ruby_math::define(ruby, &module)?;
|
|
22
|
+
ruby_query::define(ruby, &module)?;
|
|
23
|
+
ruby_system::define(ruby, &module)?;
|
|
24
|
+
ruby_world::define(ruby, &module)?;
|
|
25
|
+
ruby_entity::define(ruby, &module)?;
|
|
26
|
+
ruby_render_app::define(ruby, &module)?;
|
|
27
|
+
|
|
28
|
+
Ok(())
|
|
29
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
use bevy_ruby::{AppBuilder, WorldWrapper};
|
|
2
|
+
use bevy_ruby::system::ScheduleLabel;
|
|
3
|
+
use magnus::{function, method, prelude::*, Error, RModule, Ruby, Symbol};
|
|
4
|
+
use std::cell::RefCell;
|
|
5
|
+
use std::sync::Arc;
|
|
6
|
+
|
|
7
|
+
use crate::ruby_world::RubyWorld;
|
|
8
|
+
|
|
9
|
+
#[magnus::wrap(class = "Bevy::AppBuilder", free_immediately, size)]
|
|
10
|
+
pub struct RubyAppBuilder {
|
|
11
|
+
inner: RefCell<AppBuilder>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl RubyAppBuilder {
|
|
15
|
+
fn new() -> Self {
|
|
16
|
+
Self {
|
|
17
|
+
inner: RefCell::new(AppBuilder::new()),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fn add_system(&self, schedule: Symbol, _param_types: Vec<String>) -> Result<(), Error> {
|
|
22
|
+
let ruby = Ruby::get().unwrap();
|
|
23
|
+
let schedule_str = schedule.name().map_err(|e| {
|
|
24
|
+
Error::new(ruby.exception_runtime_error(), format!("Invalid schedule symbol: {}", e))
|
|
25
|
+
})?;
|
|
26
|
+
let label = ScheduleLabel::from_str(&schedule_str).map_err(|e| {
|
|
27
|
+
Error::new(ruby.exception_runtime_error(), e.to_string())
|
|
28
|
+
})?;
|
|
29
|
+
let descriptor = bevy_ruby::system::SystemDescriptor::new(label);
|
|
30
|
+
self.inner.borrow_mut().add_system(descriptor);
|
|
31
|
+
Ok(())
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn systems_for_schedule(&self, schedule: Symbol) -> Result<usize, Error> {
|
|
35
|
+
let ruby = Ruby::get().unwrap();
|
|
36
|
+
let schedule_str = schedule.name().map_err(|e| {
|
|
37
|
+
Error::new(ruby.exception_runtime_error(), format!("Invalid schedule symbol: {}", e))
|
|
38
|
+
})?;
|
|
39
|
+
let label = ScheduleLabel::from_str(&schedule_str).map_err(|e| {
|
|
40
|
+
Error::new(ruby.exception_runtime_error(), e.to_string())
|
|
41
|
+
})?;
|
|
42
|
+
Ok(self.inner.borrow().systems_for_schedule(label).len())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fn create_world(&self) -> RubyWorld {
|
|
46
|
+
RubyWorld::from_wrapper(self.inner.borrow().create_world())
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#[allow(dead_code)]
|
|
50
|
+
pub fn inner(&self) -> std::cell::Ref<'_, AppBuilder> {
|
|
51
|
+
self.inner.borrow()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
unsafe impl Send for RubyAppBuilder {}
|
|
56
|
+
|
|
57
|
+
pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
|
58
|
+
let class = module.define_class("AppBuilder", ruby.class_object())?;
|
|
59
|
+
class.define_singleton_method("new", function!(RubyAppBuilder::new, 0))?;
|
|
60
|
+
class.define_method("add_system", method!(RubyAppBuilder::add_system, 2))?;
|
|
61
|
+
class.define_method("systems_for_schedule", method!(RubyAppBuilder::systems_for_schedule, 1))?;
|
|
62
|
+
class.define_method("create_world", method!(RubyAppBuilder::create_world, 0))?;
|
|
63
|
+
|
|
64
|
+
Ok(())
|
|
65
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
use bevy_ruby::RubyColor;
|
|
2
|
+
use magnus::{function, method, prelude::*, Error, RArray, RModule, Ruby};
|
|
3
|
+
use std::cell::RefCell;
|
|
4
|
+
|
|
5
|
+
#[magnus::wrap(class = "Bevy::Color", free_immediately, size)]
|
|
6
|
+
pub struct MagnusColor {
|
|
7
|
+
inner: RefCell<RubyColor>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl MagnusColor {
|
|
11
|
+
fn new(r: f64, g: f64, b: f64, a: f64) -> Self {
|
|
12
|
+
Self {
|
|
13
|
+
inner: RefCell::new(RubyColor::new(r as f32, g as f32, b as f32, a as f32)),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn rgb(r: f64, g: f64, b: f64) -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
inner: RefCell::new(RubyColor::rgb(r as f32, g as f32, b as f32)),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fn rgba(r: f64, g: f64, b: f64, a: f64) -> Self {
|
|
24
|
+
Self {
|
|
25
|
+
inner: RefCell::new(RubyColor::rgba(r as f32, g as f32, b as f32, a as f32)),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fn from_hex(hex: String) -> Result<Self, Error> {
|
|
30
|
+
RubyColor::from_hex(&hex)
|
|
31
|
+
.map(|c| Self {
|
|
32
|
+
inner: RefCell::new(c),
|
|
33
|
+
})
|
|
34
|
+
.ok_or_else(|| Error::new(magnus::exception::arg_error(), "Invalid hex color"))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn white() -> Self {
|
|
38
|
+
Self {
|
|
39
|
+
inner: RefCell::new(RubyColor::white()),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fn black() -> Self {
|
|
44
|
+
Self {
|
|
45
|
+
inner: RefCell::new(RubyColor::black()),
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fn red() -> Self {
|
|
50
|
+
Self {
|
|
51
|
+
inner: RefCell::new(RubyColor::red()),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fn green() -> Self {
|
|
56
|
+
Self {
|
|
57
|
+
inner: RefCell::new(RubyColor::green()),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn blue() -> Self {
|
|
62
|
+
Self {
|
|
63
|
+
inner: RefCell::new(RubyColor::blue()),
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn transparent() -> Self {
|
|
68
|
+
Self {
|
|
69
|
+
inner: RefCell::new(RubyColor::transparent()),
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn r(&self) -> f64 {
|
|
74
|
+
self.inner.borrow().r() as f64
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn g(&self) -> f64 {
|
|
78
|
+
self.inner.borrow().g() as f64
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn b(&self) -> f64 {
|
|
82
|
+
self.inner.borrow().b() as f64
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fn a(&self) -> f64 {
|
|
86
|
+
self.inner.borrow().a() as f64
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fn set_r(&self, r: f64) {
|
|
90
|
+
self.inner.borrow_mut().set_r(r as f32);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn set_g(&self, g: f64) {
|
|
94
|
+
self.inner.borrow_mut().set_g(g as f32);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn set_b(&self, b: f64) {
|
|
98
|
+
self.inner.borrow_mut().set_b(b as f32);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fn set_a(&self, a: f64) {
|
|
102
|
+
self.inner.borrow_mut().set_a(a as f32);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fn with_alpha(&self, alpha: f64) -> Self {
|
|
106
|
+
Self {
|
|
107
|
+
inner: RefCell::new(self.inner.borrow().with_alpha(alpha as f32)),
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fn to_a(&self) -> Result<RArray, Error> {
|
|
112
|
+
let ruby = Ruby::get().unwrap();
|
|
113
|
+
let arr = ruby.ary_new();
|
|
114
|
+
let c = self.inner.borrow();
|
|
115
|
+
arr.push(c.r() as f64)?;
|
|
116
|
+
arr.push(c.g() as f64)?;
|
|
117
|
+
arr.push(c.b() as f64)?;
|
|
118
|
+
arr.push(c.a() as f64)?;
|
|
119
|
+
Ok(arr)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
unsafe impl Send for MagnusColor {}
|
|
124
|
+
|
|
125
|
+
pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
|
126
|
+
let color_class = module.define_class("Color", ruby.class_object())?;
|
|
127
|
+
color_class.define_singleton_method("new", function!(MagnusColor::new, 4))?;
|
|
128
|
+
color_class.define_singleton_method("rgb", function!(MagnusColor::rgb, 3))?;
|
|
129
|
+
color_class.define_singleton_method("rgba", function!(MagnusColor::rgba, 4))?;
|
|
130
|
+
color_class.define_singleton_method("from_hex", function!(MagnusColor::from_hex, 1))?;
|
|
131
|
+
color_class.define_singleton_method("white", function!(MagnusColor::white, 0))?;
|
|
132
|
+
color_class.define_singleton_method("black", function!(MagnusColor::black, 0))?;
|
|
133
|
+
color_class.define_singleton_method("red", function!(MagnusColor::red, 0))?;
|
|
134
|
+
color_class.define_singleton_method("green", function!(MagnusColor::green, 0))?;
|
|
135
|
+
color_class.define_singleton_method("blue", function!(MagnusColor::blue, 0))?;
|
|
136
|
+
color_class.define_singleton_method("transparent", function!(MagnusColor::transparent, 0))?;
|
|
137
|
+
color_class.define_method("r", method!(MagnusColor::r, 0))?;
|
|
138
|
+
color_class.define_method("g", method!(MagnusColor::g, 0))?;
|
|
139
|
+
color_class.define_method("b", method!(MagnusColor::b, 0))?;
|
|
140
|
+
color_class.define_method("a", method!(MagnusColor::a, 0))?;
|
|
141
|
+
color_class.define_method("r=", method!(MagnusColor::set_r, 1))?;
|
|
142
|
+
color_class.define_method("g=", method!(MagnusColor::set_g, 1))?;
|
|
143
|
+
color_class.define_method("b=", method!(MagnusColor::set_b, 1))?;
|
|
144
|
+
color_class.define_method("a=", method!(MagnusColor::set_a, 1))?;
|
|
145
|
+
color_class.define_method("with_alpha", method!(MagnusColor::with_alpha, 1))?;
|
|
146
|
+
color_class.define_method("to_a", method!(MagnusColor::to_a, 0))?;
|
|
147
|
+
|
|
148
|
+
Ok(())
|
|
149
|
+
}
|