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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +4279 -0
  3. data/Cargo.toml +36 -0
  4. data/README.md +226 -0
  5. data/crates/bevy/Cargo.toml +52 -0
  6. data/crates/bevy/src/app.rs +43 -0
  7. data/crates/bevy/src/component.rs +111 -0
  8. data/crates/bevy/src/entity.rs +30 -0
  9. data/crates/bevy/src/error.rs +32 -0
  10. data/crates/bevy/src/event.rs +190 -0
  11. data/crates/bevy/src/input_bridge.rs +300 -0
  12. data/crates/bevy/src/lib.rs +42 -0
  13. data/crates/bevy/src/mesh_renderer.rs +328 -0
  14. data/crates/bevy/src/query.rs +53 -0
  15. data/crates/bevy/src/render_app.rs +689 -0
  16. data/crates/bevy/src/resource.rs +28 -0
  17. data/crates/bevy/src/schedule.rs +186 -0
  18. data/crates/bevy/src/sprite_renderer.rs +355 -0
  19. data/crates/bevy/src/system.rs +44 -0
  20. data/crates/bevy/src/text_renderer.rs +258 -0
  21. data/crates/bevy/src/types/color.rs +114 -0
  22. data/crates/bevy/src/types/dynamic.rs +131 -0
  23. data/crates/bevy/src/types/math.rs +260 -0
  24. data/crates/bevy/src/types/mod.rs +9 -0
  25. data/crates/bevy/src/types/transform.rs +166 -0
  26. data/crates/bevy/src/world.rs +163 -0
  27. data/crates/bevy_ruby_render/Cargo.toml +22 -0
  28. data/crates/bevy_ruby_render/src/asset.rs +360 -0
  29. data/crates/bevy_ruby_render/src/audio.rs +511 -0
  30. data/crates/bevy_ruby_render/src/camera.rs +365 -0
  31. data/crates/bevy_ruby_render/src/gamepad.rs +398 -0
  32. data/crates/bevy_ruby_render/src/lib.rs +26 -0
  33. data/crates/bevy_ruby_render/src/material.rs +310 -0
  34. data/crates/bevy_ruby_render/src/mesh.rs +491 -0
  35. data/crates/bevy_ruby_render/src/sprite.rs +289 -0
  36. data/ext/bevy/Cargo.toml +20 -0
  37. data/ext/bevy/extconf.rb +6 -0
  38. data/ext/bevy/src/conversions.rs +137 -0
  39. data/ext/bevy/src/lib.rs +29 -0
  40. data/ext/bevy/src/ruby_app.rs +65 -0
  41. data/ext/bevy/src/ruby_color.rs +149 -0
  42. data/ext/bevy/src/ruby_component.rs +189 -0
  43. data/ext/bevy/src/ruby_entity.rs +33 -0
  44. data/ext/bevy/src/ruby_math.rs +384 -0
  45. data/ext/bevy/src/ruby_query.rs +64 -0
  46. data/ext/bevy/src/ruby_render_app.rs +779 -0
  47. data/ext/bevy/src/ruby_system.rs +122 -0
  48. data/ext/bevy/src/ruby_world.rs +107 -0
  49. data/lib/bevy/animation.rb +597 -0
  50. data/lib/bevy/app.rb +675 -0
  51. data/lib/bevy/asset.rb +613 -0
  52. data/lib/bevy/audio.rb +545 -0
  53. data/lib/bevy/audio_effects.rb +224 -0
  54. data/lib/bevy/camera.rb +412 -0
  55. data/lib/bevy/component.rb +91 -0
  56. data/lib/bevy/diagnostics.rb +227 -0
  57. data/lib/bevy/ecs_advanced.rb +296 -0
  58. data/lib/bevy/event.rb +199 -0
  59. data/lib/bevy/gizmos.rb +158 -0
  60. data/lib/bevy/gltf.rb +227 -0
  61. data/lib/bevy/hierarchy.rb +444 -0
  62. data/lib/bevy/input.rb +514 -0
  63. data/lib/bevy/lighting.rb +369 -0
  64. data/lib/bevy/material.rb +248 -0
  65. data/lib/bevy/mesh.rb +257 -0
  66. data/lib/bevy/navigation.rb +344 -0
  67. data/lib/bevy/networking.rb +335 -0
  68. data/lib/bevy/particle.rb +337 -0
  69. data/lib/bevy/physics.rb +396 -0
  70. data/lib/bevy/plugins/default_plugins.rb +34 -0
  71. data/lib/bevy/plugins/input_plugin.rb +49 -0
  72. data/lib/bevy/reflect.rb +361 -0
  73. data/lib/bevy/render_graph.rb +210 -0
  74. data/lib/bevy/resource.rb +185 -0
  75. data/lib/bevy/scene.rb +254 -0
  76. data/lib/bevy/shader.rb +319 -0
  77. data/lib/bevy/shape.rb +195 -0
  78. data/lib/bevy/skeletal.rb +248 -0
  79. data/lib/bevy/sprite.rb +152 -0
  80. data/lib/bevy/sprite_sheet.rb +444 -0
  81. data/lib/bevy/state.rb +277 -0
  82. data/lib/bevy/system.rb +206 -0
  83. data/lib/bevy/text.rb +99 -0
  84. data/lib/bevy/text_advanced.rb +455 -0
  85. data/lib/bevy/timer.rb +147 -0
  86. data/lib/bevy/transform.rb +158 -0
  87. data/lib/bevy/ui.rb +454 -0
  88. data/lib/bevy/ui_advanced.rb +568 -0
  89. data/lib/bevy/version.rb +5 -0
  90. data/lib/bevy/visibility.rb +250 -0
  91. data/lib/bevy/window.rb +302 -0
  92. data/lib/bevy.rb +390 -0
  93. 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
+ }
@@ -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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+ require 'rb_sys/mkmf'
5
+
6
+ create_rust_makefile('bevy/bevy')
@@ -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
+ }
@@ -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
+ }