+259
Cargo.lock
+259
Cargo.lock
···
104
]
105
106
[[package]]
107
name = "alsa"
108
version = "0.9.1"
109
source = "registry+https://github.com/rust-lang/crates.io-index"
···
181
dependencies = [
182
"num-traits",
183
]
184
185
[[package]]
186
name = "arrayref"
···
1579
]
1580
1581
[[package]]
1582
name = "bindgen"
1583
version = "0.72.1"
1584
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1593
"regex",
1594
"rustc-hash 2.1.1",
1595
"shlex",
1596
"syn",
1597
]
1598
···
1678
]
1679
1680
[[package]]
1681
name = "bumpalo"
1682
version = "3.19.1"
1683
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2060
]
2061
2062
[[package]]
2063
name = "crc32fast"
2064
version = "1.5.0"
2065
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2348
]
2349
2350
[[package]]
2351
name = "felix-audio"
2352
version = "0.1.0"
2353
dependencies = [
···
2368
"bevy",
2369
"bevy_mod_openxr",
2370
"bevy_mod_xr",
2371
"cpal 0.16.0",
2372
"dotenvy",
2373
"felix-audio",
2374
"felix-net",
2375
"openxr",
···
3130
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
3131
3132
[[package]]
3133
name = "mach2"
3134
version = "0.4.3"
3135
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3400
dependencies = [
3401
"autocfg",
3402
"libm",
3403
]
3404
3405
[[package]]
···
3784
]
3785
3786
[[package]]
3787
name = "opus"
3788
version = "0.3.0"
3789
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3819
dependencies = [
3820
"ttf-parser 0.25.1",
3821
]
3822
3823
[[package]]
3824
name = "parking"
···
4400
]
4401
4402
[[package]]
4403
name = "serde_core"
4404
version = "1.0.228"
4405
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4430
"ryu",
4431
"serde",
4432
"serde_core",
4433
]
4434
4435
[[package]]
···
5110
version = "0.2.6"
5111
source = "registry+https://github.com/rust-lang/crates.io-index"
5112
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
5113
5114
[[package]]
5115
name = "uuid"
···
104
]
105
106
[[package]]
107
+
name = "alloc-no-stdlib"
108
+
version = "2.0.4"
109
+
source = "registry+https://github.com/rust-lang/crates.io-index"
110
+
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
111
+
112
+
[[package]]
113
+
name = "alloc-stdlib"
114
+
version = "0.2.2"
115
+
source = "registry+https://github.com/rust-lang/crates.io-index"
116
+
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
117
+
dependencies = [
118
+
"alloc-no-stdlib",
119
+
]
120
+
121
+
[[package]]
122
name = "alsa"
123
version = "0.9.1"
124
source = "registry+https://github.com/rust-lang/crates.io-index"
···
196
dependencies = [
197
"num-traits",
198
]
199
+
200
+
[[package]]
201
+
name = "array-init"
202
+
version = "2.1.0"
203
+
source = "registry+https://github.com/rust-lang/crates.io-index"
204
+
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
205
206
[[package]]
207
name = "arrayref"
···
1600
]
1601
1602
[[package]]
1603
+
name = "bevy_xr_utils"
1604
+
version = "0.4.0"
1605
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1606
+
checksum = "f82cd353262258aae6048ccad3544b8a978a301d9eb954d66efef6dccc91dfa9"
1607
+
dependencies = [
1608
+
"bevy_app",
1609
+
"bevy_color",
1610
+
"bevy_derive",
1611
+
"bevy_ecs",
1612
+
"bevy_gizmos",
1613
+
"bevy_log",
1614
+
"bevy_math",
1615
+
"bevy_mod_openxr",
1616
+
"bevy_mod_xr",
1617
+
"bevy_transform",
1618
+
"openxr",
1619
+
"openxr_mndx_xdev_space",
1620
+
]
1621
+
1622
+
[[package]]
1623
name = "bindgen"
1624
version = "0.72.1"
1625
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1634
"regex",
1635
"rustc-hash 2.1.1",
1636
"shlex",
1637
+
"syn",
1638
+
]
1639
+
1640
+
[[package]]
1641
+
name = "binrw"
1642
+
version = "0.15.0"
1643
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1644
+
checksum = "81419ff39e6ed10a92a7f125290859776ced35d9a08a665ae40b23e7ca702f30"
1645
+
dependencies = [
1646
+
"array-init",
1647
+
"binrw_derive",
1648
+
"bytemuck",
1649
+
]
1650
+
1651
+
[[package]]
1652
+
name = "binrw_derive"
1653
+
version = "0.15.0"
1654
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1655
+
checksum = "376404e55ec40d0d6f8b4b7df3f87b87954bd987f0cf9a7207ea3b6ea5c9add4"
1656
+
dependencies = [
1657
+
"either",
1658
+
"owo-colors",
1659
+
"proc-macro2",
1660
+
"quote",
1661
"syn",
1662
]
1663
···
1743
]
1744
1745
[[package]]
1746
+
name = "brotli"
1747
+
version = "3.5.0"
1748
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1749
+
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
1750
+
dependencies = [
1751
+
"alloc-no-stdlib",
1752
+
"alloc-stdlib",
1753
+
"brotli-decompressor",
1754
+
]
1755
+
1756
+
[[package]]
1757
+
name = "brotli-decompressor"
1758
+
version = "2.5.1"
1759
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1760
+
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
1761
+
dependencies = [
1762
+
"alloc-no-stdlib",
1763
+
"alloc-stdlib",
1764
+
]
1765
+
1766
+
[[package]]
1767
name = "bumpalo"
1768
version = "3.19.1"
1769
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2146
]
2147
2148
[[package]]
2149
+
name = "crc"
2150
+
version = "3.4.0"
2151
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2152
+
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
2153
+
dependencies = [
2154
+
"crc-catalog",
2155
+
]
2156
+
2157
+
[[package]]
2158
+
name = "crc-catalog"
2159
+
version = "2.4.0"
2160
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2161
+
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
2162
+
2163
+
[[package]]
2164
name = "crc32fast"
2165
version = "1.5.0"
2166
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2449
]
2450
2451
[[package]]
2452
+
name = "felix-assets"
2453
+
version = "0.1.0"
2454
+
dependencies = [
2455
+
"anyhow",
2456
+
"bevy",
2457
+
"unity-asset",
2458
+
"unity-asset-binary",
2459
+
"unity-asset-decode",
2460
+
]
2461
+
2462
+
[[package]]
2463
name = "felix-audio"
2464
version = "0.1.0"
2465
dependencies = [
···
2480
"bevy",
2481
"bevy_mod_openxr",
2482
"bevy_mod_xr",
2483
+
"bevy_xr_utils",
2484
"cpal 0.16.0",
2485
"dotenvy",
2486
+
"felix-assets",
2487
"felix-audio",
2488
"felix-net",
2489
"openxr",
···
3244
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
3245
3246
[[package]]
3247
+
name = "lz4_flex"
3248
+
version = "0.12.0"
3249
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3250
+
checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e"
3251
+
dependencies = [
3252
+
"twox-hash",
3253
+
]
3254
+
3255
+
[[package]]
3256
+
name = "lzma-rs"
3257
+
version = "0.3.0"
3258
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3259
+
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
3260
+
dependencies = [
3261
+
"byteorder",
3262
+
"crc",
3263
+
]
3264
+
3265
+
[[package]]
3266
name = "mach2"
3267
version = "0.4.3"
3268
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3533
dependencies = [
3534
"autocfg",
3535
"libm",
3536
+
]
3537
+
3538
+
[[package]]
3539
+
name = "num_cpus"
3540
+
version = "1.17.0"
3541
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3542
+
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
3543
+
dependencies = [
3544
+
"hermit-abi",
3545
+
"libc",
3546
]
3547
3548
[[package]]
···
3927
]
3928
3929
[[package]]
3930
+
name = "openxr_mndx_xdev_space"
3931
+
version = "0.1.1"
3932
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3933
+
checksum = "fc03c3948dceb287224eaa9079a5d4f690e91b43a2385da6c686edf0f850408a"
3934
+
dependencies = [
3935
+
"openxr",
3936
+
]
3937
+
3938
+
[[package]]
3939
name = "opus"
3940
version = "0.3.0"
3941
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3971
dependencies = [
3972
"ttf-parser 0.25.1",
3973
]
3974
+
3975
+
[[package]]
3976
+
name = "owo-colors"
3977
+
version = "4.2.3"
3978
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3979
+
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
3980
3981
[[package]]
3982
name = "parking"
···
4558
]
4559
4560
[[package]]
4561
+
name = "serde_bytes"
4562
+
version = "0.11.19"
4563
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4564
+
checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
4565
+
dependencies = [
4566
+
"serde",
4567
+
"serde_core",
4568
+
]
4569
+
4570
+
[[package]]
4571
name = "serde_core"
4572
version = "1.0.228"
4573
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4598
"ryu",
4599
"serde",
4600
"serde_core",
4601
+
]
4602
+
4603
+
[[package]]
4604
+
name = "serde_yaml"
4605
+
version = "0.9.34+deprecated"
4606
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4607
+
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
4608
+
dependencies = [
4609
+
"indexmap",
4610
+
"itoa",
4611
+
"ryu",
4612
+
"serde",
4613
+
"unsafe-libyaml",
4614
]
4615
4616
[[package]]
···
5291
version = "0.2.6"
5292
source = "registry+https://github.com/rust-lang/crates.io-index"
5293
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
5294
+
5295
+
[[package]]
5296
+
name = "unity-asset"
5297
+
version = "0.2.0"
5298
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5299
+
checksum = "6705b95fda449527055ff77fe5cff49f774dde7335ed92bc3d048fc74066ebaf"
5300
+
dependencies = [
5301
+
"unity-asset-binary",
5302
+
"unity-asset-core",
5303
+
"unity-asset-yaml",
5304
+
]
5305
+
5306
+
[[package]]
5307
+
name = "unity-asset-binary"
5308
+
version = "0.2.0"
5309
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5310
+
checksum = "d739d1414c1732be1035417f83b1e60f234c7d5eb8abda0ee70d178a58137cb7"
5311
+
dependencies = [
5312
+
"binrw",
5313
+
"brotli",
5314
+
"byteorder",
5315
+
"flate2",
5316
+
"indexmap",
5317
+
"lz4_flex",
5318
+
"lzma-rs",
5319
+
"memmap2",
5320
+
"num_cpus",
5321
+
"once_cell",
5322
+
"regex",
5323
+
"serde",
5324
+
"serde_json",
5325
+
"thiserror 2.0.17",
5326
+
"unity-asset-core",
5327
+
]
5328
+
5329
+
[[package]]
5330
+
name = "unity-asset-core"
5331
+
version = "0.2.0"
5332
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5333
+
checksum = "12903fd47e122b5e7e335fc9cb5540bb35ab0ffe5bb57a7741a8c7be8d361361"
5334
+
dependencies = [
5335
+
"indexmap",
5336
+
"lazy_static",
5337
+
"serde",
5338
+
"serde_bytes",
5339
+
"thiserror 2.0.17",
5340
+
]
5341
+
5342
+
[[package]]
5343
+
name = "unity-asset-decode"
5344
+
version = "0.2.0"
5345
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5346
+
checksum = "9ea6e630cdefde54a88ca4fbae54cf3d3e5ba527fac96b085562da3b3834b77b"
5347
+
dependencies = [
5348
+
"indexmap",
5349
+
"serde",
5350
+
"unity-asset-binary",
5351
+
"unity-asset-core",
5352
+
]
5353
+
5354
+
[[package]]
5355
+
name = "unity-asset-yaml"
5356
+
version = "0.2.0"
5357
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5358
+
checksum = "b991e340c27b1578e657defee9f57de867d853b8f40448fb079d0ee3a5ebc77e"
5359
+
dependencies = [
5360
+
"indexmap",
5361
+
"serde",
5362
+
"serde_yaml",
5363
+
"thiserror 2.0.17",
5364
+
"unity-asset-core",
5365
+
]
5366
+
5367
+
[[package]]
5368
+
name = "unsafe-libyaml"
5369
+
version = "0.2.11"
5370
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5371
+
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
5372
5373
[[package]]
5374
name = "uuid"
+4
-1
Cargo.toml
+4
-1
Cargo.toml
+11
assets/Cargo.toml
+11
assets/Cargo.toml
+3
assets/examples/test.rs
+3
assets/examples/test.rs
+62
assets/src/buffer.rs
+62
assets/src/buffer.rs
···
···
1
+
use std::io::Read;
2
+
3
+
use bevy::math::{Quat, Vec3};
4
+
5
+
pub struct StreamedBuffer{
6
+
stream: Box<dyn Read>
7
+
}
8
+
9
+
impl StreamedBuffer{
10
+
pub fn new( stream: impl Read + 'static ) -> Self{
11
+
Self {
12
+
stream: Box::new(stream)
13
+
}
14
+
}
15
+
16
+
pub fn get_u8(&mut self) -> u8{
17
+
let mut b = [0u8; 1];
18
+
self.stream.read(&mut b).unwrap();
19
+
20
+
b[0]
21
+
}
22
+
23
+
pub fn get_u8s(&mut self, count: usize) -> Vec<u8>{
24
+
let mut b = vec![0u8; count];
25
+
self.stream.read(&mut b).unwrap();
26
+
27
+
b
28
+
}
29
+
30
+
pub fn get_i32(&mut self) -> i32{
31
+
let b = self.get_u8s(4);
32
+
i32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
33
+
}
34
+
35
+
pub fn get_u32(&mut self) -> u32{
36
+
let b = self.get_u8s(4);
37
+
u32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
38
+
}
39
+
40
+
pub fn get_str(&mut self) -> String{
41
+
let length = self.get_u32();
42
+
let b = self.get_u8s(length as usize);
43
+
44
+
let string = str::from_utf8(&b).unwrap();
45
+
string.to_owned()
46
+
}
47
+
48
+
49
+
pub fn get_vec3(&mut self) -> Vec3{
50
+
Vec3 { x: self.get_f32(), y: self.get_f32(), z: self.get_f32() }
51
+
}
52
+
53
+
pub fn get_quat(&mut self) -> Quat{
54
+
Quat::from_xyzw(self.get_f32(), self.get_f32(), self.get_f32(), self.get_f32())
55
+
}
56
+
57
+
58
+
pub fn get_f32(&mut self) -> f32{
59
+
let b = self.get_u8s(4);
60
+
f32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
61
+
}
62
+
}
+84
assets/src/felix/mod.rs
+84
assets/src/felix/mod.rs
···
···
1
+
use std::fs::File;
2
+
3
+
use bevy::{asset::RenderAssetUsages, mesh::{Indices, PrimitiveTopology}, prelude::*, transform::components::Transform};
4
+
5
+
use crate::{BevyObject, BevyObjectData, BevyObjectLightData, BevyObjectLightDataType, buffer::StreamedBuffer};
6
+
7
+
pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{
8
+
// TODO: Material loading
9
+
// TODO: UV Loading
10
+
// TODO: Flat normals
11
+
// TODO: Live updates directly from blender?
12
+
13
+
let mut objs = vec![];
14
+
15
+
let decoder = File::open(path).unwrap();
16
+
let mut buf = StreamedBuffer::new(decoder);
17
+
18
+
let obj_count = buf.get_u32();
19
+
20
+
for _ in 0..obj_count{
21
+
let name = buf.get_str();
22
+
let transform = Transform {
23
+
translation: buf.get_vec3(),
24
+
rotation: buf.get_quat(),
25
+
scale: buf.get_vec3()
26
+
};
27
+
28
+
match buf.get_u32(){
29
+
0 => { // 0 - Mesh
30
+
let mut vertices = vec![];
31
+
let mut normals = vec![];
32
+
let mut triangles = vec![];
33
+
34
+
let vertex_count = buf.get_u32();
35
+
for _ in 0..vertex_count{
36
+
vertices.push(buf.get_vec3());
37
+
normals.push(buf.get_vec3());
38
+
}
39
+
40
+
let triangle_count = buf.get_u32();
41
+
for _ in 0..triangle_count{
42
+
triangles.push(buf.get_u32());
43
+
triangles.push(buf.get_u32());
44
+
triangles.push(buf.get_u32());
45
+
}
46
+
47
+
objs.push(BevyObject {
48
+
name,
49
+
transform,
50
+
data: BevyObjectData::Mesh(Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD)
51
+
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
52
+
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
53
+
.with_inserted_indices(Indices::U32(triangles)))
54
+
});
55
+
}
56
+
57
+
1 => { // 1 - Light
58
+
let light_type = match buf.get_u32(){
59
+
0 => BevyObjectLightDataType::Point,
60
+
1 => BevyObjectLightDataType::Sun,
61
+
2 => BevyObjectLightDataType::Spot,
62
+
3 => BevyObjectLightDataType::Area,
63
+
_ => BevyObjectLightDataType::Unknown
64
+
};
65
+
66
+
let colour = buf.get_vec3();
67
+
68
+
objs.push(BevyObject {
69
+
name,
70
+
transform,
71
+
data: BevyObjectData::Light(BevyObjectLightData {
72
+
type_: light_type,
73
+
colour: Color::linear_rgb(colour.x, colour.y, colour.z),
74
+
power: buf.get_f32()
75
+
})
76
+
});
77
+
}
78
+
79
+
_ => {}
80
+
}
81
+
}
82
+
83
+
Ok(objs)
84
+
}
+38
assets/src/lib.rs
+38
assets/src/lib.rs
···
···
1
+
use bevy::{color::Color, mesh::Mesh, transform::components::Transform};
2
+
3
+
mod unity;
4
+
mod felix;
5
+
mod buffer;
6
+
7
+
#[derive(Debug)]
8
+
pub enum BevyObjectData{
9
+
Mesh(Mesh),
10
+
Light(BevyObjectLightData)
11
+
}
12
+
13
+
#[derive(Debug)]
14
+
pub struct BevyObject{
15
+
pub name: String,
16
+
pub transform: Transform,
17
+
pub data: BevyObjectData,
18
+
}
19
+
20
+
#[derive(Debug)]
21
+
pub struct BevyObjectLightData{
22
+
pub type_: BevyObjectLightDataType,
23
+
pub colour: Color,
24
+
pub power: f32
25
+
}
26
+
27
+
#[derive(Debug)]
28
+
pub enum BevyObjectLightDataType{
29
+
Point,
30
+
Sun,
31
+
Spot,
32
+
Area,
33
+
Unknown
34
+
}
35
+
36
+
pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{
37
+
felix::load(path)
38
+
}
+22
assets/src/unity/component/mesh_renderer.rs
+22
assets/src/unity/component/mesh_renderer.rs
···
···
1
+
use unity_asset_binary::object::UnityObject;
2
+
3
+
use crate::unity::component::Component;
4
+
5
+
#[derive(Debug)]
6
+
pub struct MeshRenderer{
7
+
8
+
}
9
+
10
+
impl Component for MeshRenderer{
11
+
12
+
}
13
+
14
+
impl From<UnityObject> for MeshRenderer{
15
+
fn from(value: UnityObject) -> Self {
16
+
// dbg!(value.property_names());
17
+
18
+
Self {
19
+
20
+
}
21
+
}
22
+
}
+6
assets/src/unity/component/mod.rs
+6
assets/src/unity/component/mod.rs
+16
assets/src/unity/component/transform.rs
+16
assets/src/unity/component/transform.rs
···
···
1
+
use bevy::transform::components::Transform;
2
+
use unity_asset_binary::object::UnityObject;
3
+
4
+
use crate::unity::unity_value::{unity_value_to_quat, unity_value_to_vec3};
5
+
6
+
pub fn into_bevy_transform(value: UnityObject) -> Transform {
7
+
let position = value.get("m_LocalPosition").unwrap();
8
+
let rotation = value.get("m_LocalRotation").unwrap();
9
+
let scale = value.get("m_LocalScale").unwrap();
10
+
11
+
Transform {
12
+
translation: unity_value_to_vec3(position),
13
+
rotation: unity_value_to_quat(rotation),
14
+
scale: unity_value_to_vec3(scale)
15
+
}
16
+
}
+111
assets/src/unity/mod.rs
+111
assets/src/unity/mod.rs
···
···
1
+
// NOTE: Very WIP, Does not work!!
2
+
3
+
use anyhow::bail;
4
+
use bevy::{prelude::*, transform::components::Transform};
5
+
use unity_asset::environment::{Environment, EnvironmentObjectRef};
6
+
use unity_asset_binary::unity_version::UnityVersion;
7
+
use unity_asset_decode::mesh::MeshParser;
8
+
9
+
use crate::{BevyObject, BevyObjectData, unity::{component::{Component, mesh_renderer::MeshRenderer, transform::into_bevy_transform}, unity_value::try_unity_mesh_to_bevy}};
10
+
11
+
mod component;
12
+
mod unity_value;
13
+
14
+
#[derive(Debug)]
15
+
pub struct UnityGameObject{
16
+
pub name: String,
17
+
pub active: bool,
18
+
19
+
pub transform: Transform,
20
+
pub mesh_renderer: Option<MeshRenderer>,
21
+
pub mesh_filter: Option<Mesh>,
22
+
}
23
+
24
+
pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{
25
+
let mesh_parser = MeshParser::new(UnityVersion::parse_version("2020.3.12f1").unwrap());
26
+
27
+
let mut env = Environment::new();
28
+
env.load(path)?;
29
+
30
+
let mut gameobjects = vec![];
31
+
32
+
for obj in env.objects(){
33
+
match obj{
34
+
EnvironmentObjectRef::Binary(v) => {
35
+
if v.object.class_id() == 1{
36
+
let obj = v.object.read()?;
37
+
let go = obj.as_gameobject().unwrap();
38
+
39
+
let mut components: Vec<Box<dyn Component>> = vec![];
40
+
41
+
let mut transform = None;
42
+
let mut mesh_renderer = None;
43
+
let mut mesh_filter = None;
44
+
45
+
let comps = obj.get("m_Component").unwrap().as_array().unwrap();
46
+
47
+
for comp in comps{
48
+
let obj = comp.as_object().unwrap().get("component").unwrap();
49
+
let path_id = obj.as_object().unwrap().get("m_PathID").unwrap().as_i64().unwrap();
50
+
51
+
let comp = env.find_binary_object(path_id).unwrap();
52
+
let comp = comp.read().unwrap();
53
+
54
+
match comp.class_id(){
55
+
4 => transform = Some(into_bevy_transform(comp)), // Normal Transform
56
+
224 => transform = Some(into_bevy_transform(comp)), // Rect Transform (gonna just treat it as normal)
57
+
58
+
23 => mesh_renderer = Some(MeshRenderer::from(comp)),
59
+
33 => {
60
+
let mesh = comp.get("m_Mesh").unwrap();
61
+
let path_id = mesh.as_object().unwrap().get("m_PathID").unwrap().as_i64().unwrap();
62
+
63
+
let mesh = env.find_binary_object(path_id).unwrap();
64
+
let mesh_obj = mesh.read().unwrap();
65
+
66
+
if let Some(mesh) = try_unity_mesh_to_bevy(mesh_obj, &mesh_parser){
67
+
mesh_filter = Some(mesh);
68
+
} else{
69
+
println!("[WARN] Failed to load mesh for: {}", go.name);
70
+
}
71
+
},
72
+
73
+
_ => {}
74
+
}
75
+
}
76
+
77
+
if transform.is_none(){ bail!("Cannot find transform for object {}", go.name); }
78
+
79
+
let gameobject = UnityGameObject {
80
+
name: go.name,
81
+
active: go.active,
82
+
83
+
transform: transform.unwrap(),
84
+
mesh_renderer,
85
+
mesh_filter
86
+
};
87
+
88
+
gameobjects.push(gameobject);
89
+
break;
90
+
}
91
+
},
92
+
_ => {}
93
+
}
94
+
}
95
+
96
+
let mut objs = vec![];
97
+
98
+
for go in gameobjects{
99
+
if go.active{
100
+
if let Some(mesh) = go.mesh_filter{
101
+
objs.push(BevyObject {
102
+
name: go.name,
103
+
transform: go.transform,
104
+
data: BevyObjectData::Mesh(mesh)
105
+
});
106
+
}
107
+
}
108
+
}
109
+
110
+
Ok(objs)
111
+
}
+467
assets/src/unity/unity_value.rs
+467
assets/src/unity/unity_value.rs
···
···
1
+
use std::{fs::File, io::Write, mem};
2
+
3
+
use bevy::{asset::RenderAssetUsages, math::{Quat, Vec3}, mesh::{Indices, PrimitiveTopology}, prelude::*};
4
+
use unity_asset::UnityValue;
5
+
use unity_asset_binary::object::UnityObject;
6
+
use unity_asset_decode::mesh::MeshParser;
7
+
8
+
pub fn unity_value_to_vec3( val: &UnityValue ) -> Vec3{
9
+
let obj = val.as_object().unwrap();
10
+
11
+
Vec3 {
12
+
x: obj.get("x").unwrap().as_f64().unwrap() as f32,
13
+
y: obj.get("y").unwrap().as_f64().unwrap() as f32,
14
+
z: obj.get("z").unwrap().as_f64().unwrap() as f32
15
+
}
16
+
}
17
+
18
+
pub fn unity_value_to_quat( val: &UnityValue ) -> Quat{
19
+
let obj = val.as_object().unwrap();
20
+
21
+
Quat::from_xyzw(
22
+
obj.get("x").unwrap().as_f64().unwrap() as f32,
23
+
obj.get("y").unwrap().as_f64().unwrap() as f32,
24
+
obj.get("z").unwrap().as_f64().unwrap() as f32,
25
+
obj.get("w").unwrap().as_f64().unwrap() as f32
26
+
)
27
+
}
28
+
29
+
fn get_channel_component_size( format: u8 ) -> usize{
30
+
match format{
31
+
0 => 4, // kVertexFormatFloat
32
+
1 => 2, // kVertexFormatFloat16
33
+
2 => 1, // kVertexFormatUNorm8
34
+
3 => 1, // kVertexFormatSNorm8
35
+
4 => 2, // kVertexFormatUNorm16
36
+
5 => 2, // kVertexFormatSNorm16
37
+
6 => 1, // kVertexFormatUInt8
38
+
7 => 1, // kVertexFormatSInt8
39
+
8 => 2, // kVertexFormatUInt16
40
+
9 => 2, // kVertexFormatSInt16
41
+
10 => 4, // kVertexFormatUInt32
42
+
11 => 4, // kVertexFormatSInt32
43
+
44
+
_ => 0
45
+
}
46
+
}
47
+
48
+
enum UnityDataTypeArray{
49
+
kVertexFormatFloat(Vec<Vec<f32>>),
50
+
kVertexFormatFloat16(Vec<Vec<f32>>),
51
+
kVertexFormatUNorm8(Vec<Vec<u8>>),
52
+
kVertexFormatSNorm8(Vec<Vec<i8>>),
53
+
kVertexFormatUNorm16(Vec<Vec<u16>>),
54
+
kVertexFormatSNorm16(Vec<Vec<i16>>),
55
+
kVertexFormatUInt8(Vec<Vec<u8>>),
56
+
kVertexFormatSInt8(Vec<Vec<i8>>),
57
+
kVertexFormatUInt16(Vec<Vec<u16>>),
58
+
kVertexFormatSInt16(Vec<Vec<i16>>),
59
+
kVertexFormatUInt32(Vec<Vec<u32>>),
60
+
kVertexFormatSInt32(Vec<Vec<i32>>),
61
+
Unknown
62
+
}
63
+
64
+
impl UnityDataTypeArray{
65
+
pub fn as_vec3_array( &self ) -> Vec<Vec3>{
66
+
if let Self::kVertexFormatFloat(array) = self{
67
+
let mut vecs = vec![];
68
+
69
+
for val in array{
70
+
vecs.push(Vec3 { x: val[0], y: val[1], z: val[2] });
71
+
}
72
+
73
+
vecs
74
+
} else{
75
+
panic!("Not a float array");
76
+
}
77
+
}
78
+
}
79
+
80
+
fn unpack_struct( dimension: usize, component_dtype: u8, bytes: Vec<u8> ) -> UnityDataTypeArray{
81
+
match component_dtype{
82
+
0 => {
83
+
let mut decoded: Vec<Vec<_>> = vec![];
84
+
let item_size = get_channel_component_size(component_dtype);
85
+
let vec_size = item_size * dimension;
86
+
87
+
for i in 0..( bytes.len() / vec_size ){
88
+
let indx = i * vec_size;
89
+
let mut vec = vec![0.0; dimension];
90
+
91
+
for j in 0..dimension{
92
+
vec[j] = f32::from_le_bytes([
93
+
bytes[indx + (j * item_size)],
94
+
bytes[indx + (j * item_size) + 1],
95
+
bytes[indx + (j * item_size) + 2],
96
+
bytes[indx + (j * item_size) + 3]
97
+
]);
98
+
}
99
+
decoded.push(vec);
100
+
}
101
+
102
+
UnityDataTypeArray::kVertexFormatFloat(decoded)
103
+
},
104
+
105
+
1 => {
106
+
let mut decoded: Vec<Vec<_>> = vec![];
107
+
let item_size = get_channel_component_size(component_dtype);
108
+
let vec_size = item_size * dimension;
109
+
110
+
for i in 0..( bytes.len() / vec_size ){
111
+
let indx = i * vec_size;
112
+
let mut vec = vec![0.0; dimension];
113
+
114
+
for j in 0..dimension{
115
+
vec[j] = f32::from_le_bytes([
116
+
bytes[indx + (j * item_size)],
117
+
bytes[indx + (j * item_size) + 1],
118
+
0, 0
119
+
]);
120
+
}
121
+
decoded.push(vec);
122
+
}
123
+
124
+
UnityDataTypeArray::kVertexFormatFloat16(decoded)
125
+
},
126
+
127
+
2 => {
128
+
let mut decoded: Vec<Vec<u8>> = vec![];
129
+
let item_size = get_channel_component_size(component_dtype);
130
+
let vec_size = item_size * dimension;
131
+
132
+
for i in 0..( bytes.len() / vec_size ){
133
+
let indx = i * vec_size;
134
+
let mut vec = vec![0; vec_size];
135
+
136
+
for j in 0..vec_size{ vec[j] = u8::from_le_bytes([ bytes[indx + (j * item_size)] ]); }
137
+
decoded.push(vec);
138
+
}
139
+
140
+
UnityDataTypeArray::kVertexFormatUNorm8(decoded)
141
+
},
142
+
143
+
3 => {
144
+
let mut decoded: Vec<Vec<_>> = vec![];
145
+
let item_size = get_channel_component_size(component_dtype);
146
+
let vec_size = item_size * dimension;
147
+
148
+
for i in 0..( bytes.len() / vec_size ){
149
+
let indx = i * vec_size;
150
+
let mut vec = vec![0; vec_size];
151
+
152
+
for j in 0..vec_size{ vec[j] = i8::from_le_bytes([ bytes[indx + (j * item_size)] ]); }
153
+
decoded.push(vec);
154
+
}
155
+
156
+
UnityDataTypeArray::kVertexFormatSNorm8(decoded)
157
+
},
158
+
159
+
4 => {
160
+
let mut decoded: Vec<Vec<_>> = vec![];
161
+
let item_size = get_channel_component_size(component_dtype);
162
+
let vec_size = item_size * dimension;
163
+
164
+
for i in 0..( bytes.len() / vec_size ){
165
+
let indx = i * vec_size;
166
+
let mut vec = vec![0; vec_size];
167
+
168
+
for j in 0..vec_size{
169
+
vec[j] = u16::from_le_bytes([
170
+
bytes[indx + (j * item_size)],
171
+
bytes[indx + (j * item_size) + 1]
172
+
]);
173
+
}
174
+
decoded.push(vec);
175
+
}
176
+
177
+
UnityDataTypeArray::kVertexFormatUNorm16(decoded)
178
+
},
179
+
180
+
5 => {
181
+
let mut decoded: Vec<Vec<_>> = vec![];
182
+
let item_size = get_channel_component_size(component_dtype);
183
+
let vec_size = item_size * dimension;
184
+
185
+
for i in 0..( bytes.len() / vec_size ){
186
+
let indx = i * vec_size;
187
+
let mut vec = vec![0; vec_size];
188
+
189
+
for j in 0..vec_size{
190
+
vec[j] = i16::from_le_bytes([
191
+
bytes[indx + (j * item_size)],
192
+
bytes[indx + (j * item_size) + 1]
193
+
]);
194
+
}
195
+
decoded.push(vec);
196
+
}
197
+
198
+
UnityDataTypeArray::kVertexFormatSNorm16(decoded)
199
+
},
200
+
201
+
6 => {
202
+
let mut decoded: Vec<Vec<u8>> = vec![];
203
+
let item_size = get_channel_component_size(component_dtype);
204
+
let vec_size = item_size * dimension;
205
+
206
+
for i in 0..( bytes.len() / vec_size ){
207
+
let indx = i * vec_size;
208
+
let mut vec = vec![0; vec_size];
209
+
210
+
for j in 0..vec_size{ vec[j] = u8::from_le_bytes([ bytes[indx + (j * item_size)] ]); }
211
+
decoded.push(vec);
212
+
}
213
+
214
+
UnityDataTypeArray::kVertexFormatUInt8(decoded)
215
+
},
216
+
217
+
7 => {
218
+
let mut decoded: Vec<Vec<_>> = vec![];
219
+
let item_size = get_channel_component_size(component_dtype);
220
+
let vec_size = item_size * dimension;
221
+
222
+
for i in 0..( bytes.len() / vec_size ){
223
+
let indx = i * vec_size;
224
+
let mut vec = vec![0; vec_size];
225
+
226
+
for j in 0..vec_size{ vec[j] = i8::from_le_bytes([ bytes[indx + (j * item_size)] ]); }
227
+
decoded.push(vec);
228
+
}
229
+
230
+
UnityDataTypeArray::kVertexFormatSInt8(decoded)
231
+
},
232
+
233
+
8 => {
234
+
let mut decoded: Vec<Vec<_>> = vec![];
235
+
let item_size = get_channel_component_size(component_dtype);
236
+
let vec_size = item_size * dimension;
237
+
238
+
for i in 0..( bytes.len() / vec_size ){
239
+
let indx = i * vec_size;
240
+
let mut vec = vec![0; vec_size];
241
+
242
+
for j in 0..vec_size{
243
+
vec[j] = u16::from_le_bytes([
244
+
bytes[indx + (j * item_size)],
245
+
bytes[indx + (j * item_size) + 1]
246
+
]);
247
+
}
248
+
decoded.push(vec);
249
+
}
250
+
251
+
UnityDataTypeArray::kVertexFormatUInt16(decoded)
252
+
},
253
+
254
+
9 => {
255
+
let mut decoded: Vec<Vec<_>> = vec![];
256
+
let item_size = get_channel_component_size(component_dtype);
257
+
let vec_size = item_size * dimension;
258
+
259
+
for i in 0..( bytes.len() / vec_size ){
260
+
let indx = i * vec_size;
261
+
let mut vec = vec![0; vec_size];
262
+
263
+
for j in 0..vec_size{
264
+
vec[j] = i16::from_le_bytes([
265
+
bytes[indx + (j * item_size)],
266
+
bytes[indx + (j * item_size) + 1]
267
+
]);
268
+
}
269
+
decoded.push(vec);
270
+
}
271
+
272
+
UnityDataTypeArray::kVertexFormatSInt16(decoded)
273
+
},
274
+
275
+
10 => {
276
+
let mut decoded: Vec<Vec<_>> = vec![];
277
+
let item_size = get_channel_component_size(component_dtype);
278
+
let vec_size = item_size * dimension;
279
+
280
+
for i in 0..( bytes.len() / vec_size ){
281
+
let indx = i * vec_size;
282
+
let mut vec = vec![0; vec_size];
283
+
284
+
for j in 0..vec_size{
285
+
vec[j] = u32::from_le_bytes([
286
+
bytes[indx + (j * item_size)],
287
+
bytes[indx + (j * item_size) + 1],
288
+
bytes[indx + (j * item_size) + 2],
289
+
bytes[indx + (j * item_size) + 3]
290
+
]);
291
+
}
292
+
decoded.push(vec);
293
+
}
294
+
295
+
UnityDataTypeArray::kVertexFormatUInt32(decoded)
296
+
},
297
+
298
+
11 => {
299
+
let mut decoded: Vec<Vec<_>> = vec![];
300
+
let item_size = get_channel_component_size(component_dtype);
301
+
let vec_size = item_size * dimension;
302
+
303
+
for i in 0..( bytes.len() / vec_size ){
304
+
let indx = i * vec_size;
305
+
let mut vec = vec![0; vec_size];
306
+
307
+
for j in 0..vec_size{
308
+
vec[j] = i32::from_le_bytes([
309
+
bytes[indx + (j * item_size)],
310
+
bytes[indx + (j * item_size) + 1],
311
+
bytes[indx + (j * item_size) + 2],
312
+
bytes[indx + (j * item_size) + 3]
313
+
]);
314
+
}
315
+
decoded.push(vec);
316
+
}
317
+
318
+
UnityDataTypeArray::kVertexFormatSInt32(decoded)
319
+
},
320
+
321
+
_ => { UnityDataTypeArray::Unknown }
322
+
}
323
+
}
324
+
325
+
struct StreamInfo{
326
+
channel_mask: usize,
327
+
offset: usize,
328
+
stride: usize
329
+
}
330
+
331
+
pub fn try_unity_mesh_to_bevy( mesh_obj: UnityObject, mesh_parser: &MeshParser ) -> Option<Mesh>{
332
+
let mut vertices = None;
333
+
let mut normals = None;
334
+
let mut tangents = None;
335
+
let mut uv0 = None;
336
+
337
+
let mesh = mesh_parser.parse_from_unity_object(&mesh_obj).unwrap().mesh;
338
+
let vertex_data = mesh.vertex_data;
339
+
340
+
dbg!(&vertex_data.channels);
341
+
342
+
let mut streams = vec![];
343
+
let stream_count = 1 + vertex_data.channels.iter().map(|x| x.stream).max()? as usize;
344
+
345
+
let mut offset = 0;
346
+
347
+
for s in 0..stream_count{
348
+
let mut chn_mask = 0;
349
+
let mut stride = 0;
350
+
351
+
let mut i = 0;
352
+
for channel in &vertex_data.channels{
353
+
if channel.stream == s as u8 && channel.dimension > 0{
354
+
chn_mask |= 1 << i;
355
+
356
+
let component_size = get_channel_component_size(channel.format);
357
+
stride += channel.dimension as usize * component_size;
358
+
}
359
+
360
+
i += 1;
361
+
}
362
+
363
+
streams.push(StreamInfo {
364
+
channel_mask: chn_mask,
365
+
offset,
366
+
stride
367
+
});
368
+
369
+
offset += vertex_data.vertex_count as usize * stride;
370
+
offset = ( offset + ( 16 - 1 ) ) & !(16 - 1);
371
+
}
372
+
373
+
let mut i = 0;
374
+
for channel in vertex_data.channels{
375
+
let stream = &streams[channel.stream as usize];
376
+
377
+
if stream.channel_mask >> i & 1 == 1{
378
+
let component_byte_size = get_channel_component_size(channel.format);
379
+
dbg!(&component_byte_size, &channel.format);
380
+
let channel_dimension = channel.dimension as usize;
381
+
382
+
let mut bytes =
383
+
vec![0; vertex_data.vertex_count as usize * channel_dimension * component_byte_size];
384
+
385
+
for v in 0..vertex_data.vertex_count{
386
+
let vertex_offset = stream.offset + channel.offset as usize + stream.stride * v as usize;
387
+
388
+
for d in 0..channel_dimension{
389
+
let component_offset = vertex_offset + component_byte_size * d as usize;
390
+
let dst_offset = component_byte_size * (v as usize * channel.dimension as usize + d as usize);
391
+
392
+
let slice = &vertex_data.data_size[component_offset..component_offset + component_byte_size];
393
+
bytes[dst_offset..dst_offset + component_byte_size].clone_from_slice(slice);
394
+
}
395
+
}
396
+
397
+
let component_data = unpack_struct(channel_dimension, channel.format, bytes);
398
+
399
+
match i{
400
+
0 => vertices = Some(component_data),
401
+
1 => normals = Some(component_data),
402
+
2 => tangents = Some(component_data),
403
+
4 => uv0 = Some(component_data),
404
+
405
+
_ => {}
406
+
}
407
+
}
408
+
409
+
i += 1;
410
+
}
411
+
412
+
let mut triangles = vec![];
413
+
if mesh.index_buffer.len() > 0{
414
+
for submesh in mesh.sub_meshes{
415
+
let first_index = submesh.first_byte / 2;
416
+
417
+
match submesh.topology{
418
+
0 => {
419
+
// for i in (0..submesh.index_count).step_by(3){
420
+
// triangles.push(mesh.index_buffer[(first_index + i) as usize] as u16);
421
+
// triangles.push(mesh.index_buffer[(first_index + i + 1) as usize] as u16);
422
+
// triangles.push(mesh.index_buffer[(first_index + i + 2) as usize] as u16);
423
+
// }
424
+
425
+
for i in (0..submesh.index_count).step_by(6){
426
+
triangles.push(u16::from_le_bytes([
427
+
mesh.index_buffer[(first_index + i) as usize],
428
+
mesh.index_buffer[(first_index + i + 1) as usize]
429
+
]));
430
+
431
+
triangles.push(u16::from_le_bytes([
432
+
mesh.index_buffer[(first_index + i + 2) as usize],
433
+
mesh.index_buffer[(first_index + i + 3) as usize]
434
+
]));
435
+
436
+
triangles.push(u16::from_le_bytes([
437
+
mesh.index_buffer[(first_index + i + 4) as usize],
438
+
mesh.index_buffer[(first_index + i + 5) as usize]
439
+
]));
440
+
}
441
+
},
442
+
// TODO: Implement other topologys
443
+
_ => {}
444
+
}
445
+
}
446
+
} else{
447
+
return None;
448
+
}
449
+
450
+
if vertices.is_none(){ panic!("Cannot parse vertices") }
451
+
let vertices = vertices.unwrap().as_vec3_array();
452
+
453
+
let mut file = File::create("test.obj").unwrap();
454
+
455
+
for vec in &vertices{
456
+
writeln!(file, "v {} {} {}", vec.x, vec.y, vec.z).unwrap();
457
+
}
458
+
459
+
for i in 0..(triangles.len() / 3){
460
+
let indx = i * 3;
461
+
writeln!(file, "f {} {} {}", triangles[indx] + 1, triangles[indx + 1] + 1, triangles[indx + 2] + 1).unwrap();
462
+
}
463
+
464
+
Some(Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD)
465
+
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
466
+
.with_inserted_indices(Indices::U16(triangles)))
467
+
}
+1
-6
audio/src/source/static_source.rs
+1
-6
audio/src/source/static_source.rs
···
1
use std::{sync::{Arc, Mutex}, thread};
2
3
use bevy::transform::components::Transform;
4
-
use kira::{Decibels, Easing, Mapping, Mix, Tween, Value, effect::{filter::FilterBuilder, reverb::ReverbBuilder}, sound::static_sound::StaticSoundData, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
5
6
use crate::{FelixAudioComponent, source::AudioSource};
7
···
52
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
53
input_range: ( 0.0, 20.0 ),
54
output_range: ( 18000.0, 2000.0 ),
55
-
easing: Easing::Linear
56
-
})))
57
-
.with_effect(ReverbBuilder::new().mix(Value::FromListenerDistance(Mapping {
58
-
input_range: ( 0.0, 100.0 ),
59
-
output_range: ( Mix::DRY, Mix::WET ),
60
easing: Easing::Linear
61
})))
62
.with_send(&send_track, Value::FromListenerDistance(Mapping {
···
1
use std::{sync::{Arc, Mutex}, thread};
2
3
use bevy::transform::components::Transform;
4
+
use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, sound::static_sound::StaticSoundData, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
5
6
use crate::{FelixAudioComponent, source::AudioSource};
7
···
52
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
53
input_range: ( 0.0, 20.0 ),
54
output_range: ( 18000.0, 2000.0 ),
55
easing: Easing::Linear
56
})))
57
.with_send(&send_track, Value::FromListenerDistance(Mapping {
+1
-6
audio/src/source/stream_source.rs
+1
-6
audio/src/source/stream_source.rs
···
1
use bevy::transform::components::Transform;
2
-
use kira::{Decibels, Easing, Mapping, Mix, Tween, Value, effect::{filter::FilterBuilder, reverb::ReverbBuilder}, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
3
4
use crate::{FelixAudioComponent, source::{AudioSource, stream_source::sound_data::StreamAudioSourceSoundData}};
5
···
44
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
45
input_range: ( 0.0, 20.0 ),
46
output_range: ( 18000.0, 2000.0 ),
47
-
easing: Easing::Linear
48
-
})))
49
-
.with_effect(ReverbBuilder::new().mix(Value::FromListenerDistance(Mapping {
50
-
input_range: ( 0.0, 100.0 ),
51
-
output_range: ( Mix::DRY, Mix::WET ),
52
easing: Easing::Linear
53
})))
54
.with_send(&send_track, Value::FromListenerDistance(Mapping {
···
1
use bevy::transform::components::Transform;
2
+
use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
3
4
use crate::{FelixAudioComponent, source::{AudioSource, stream_source::sound_data::StreamAudioSourceSoundData}};
5
···
44
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
45
input_range: ( 0.0, 20.0 ),
46
output_range: ( 18000.0, 2000.0 ),
47
easing: Easing::Linear
48
})))
49
.with_send(&send_track, Value::FromListenerDistance(Mapping {
+1
-1
audio/src/voice/decoder.rs
+1
-1
audio/src/voice/decoder.rs
+34
-22
audio/src/voice/microphone.rs
+34
-22
audio/src/voice/microphone.rs
···
1
-
use std::{env, net::{ToSocketAddrs, UdpSocket}, sync::{Arc, Mutex, RwLock}};
2
3
use bevy::ecs::component::Component;
4
use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}};
···
10
#[derive(Component)]
11
pub struct VoiceChatMicrophone{
12
stream: Option<Stream>,
13
-
udp: Option<UdpSocket>,
14
muted: Arc<Mutex<bool>>,
15
-
last_rms: Arc<RwLock<isize>>
16
}
17
18
impl VoiceChatMicrophone{
19
-
pub fn new( socket: UdpSocket ) -> Self{
20
Self {
21
stream: None,
22
-
udp: Some(socket),
23
muted: Arc::new(Mutex::new(false)), // TODO: Default to muted
24
-
last_rms: Arc::new(RwLock::new(0))
25
}
26
}
27
···
58
let mut buffer = [0; MONO_20MS];
59
60
let muted = self.muted.clone();
61
-
let udp = self.udp.take().unwrap();
62
63
-
let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap();
64
65
for conf in mic.supported_input_configs().unwrap(){
66
println!("{} {:?} {} {:?}", conf.channels(), conf.buffer_size(), conf.sample_format(), conf.with_max_sample_rate());
67
}
68
69
let set_rms = self.last_rms.clone();
70
71
let stream = mic.build_input_stream(
72
&StreamConfig {
···
81
buffer_indx = 0;
82
} else{
83
for i in 0..data.len(){
84
-
if i % 2 == 0{ continue; }
85
86
buffer[buffer_indx] = data[i];
87
buffer_indx += 1;
···
89
if buffer_indx >= MONO_20MS{
90
buffer_indx = 0;
91
92
-
let mut total = 0;
93
-
for sample in buffer{ total += (sample as isize).pow(2) }
94
-
*set_rms.write().unwrap() = ( total / buffer.len() as isize ).isqrt();
95
96
-
let len = encoder.encode(&buffer, &mut output).unwrap();
97
-
let buf_to_send = output[0..len].to_vec();
98
99
-
let packet = PlayerVoicePacket {
100
-
id: "".into(), // NOTE: I know this kinda seems stupid but it's easier for me to get the player id on the server so imma just make the server fill this in.
101
-
packet: buf_to_send
102
-
};
103
104
-
let packet: Vec<u8> = packet.to_buf().into();
105
-
udp.send_to(&packet, addr).unwrap();
106
}
107
}
108
}
···
117
Ok(())
118
}
119
120
-
pub fn get_rms_of_last_packet( &self ) -> f32{
121
-
*self.last_rms.read().unwrap() as f32 / i16::MAX as f32
122
}
123
}
···
1
+
use std::{env, net::{SocketAddr, UdpSocket}, sync::{Arc, Mutex, RwLock}};
2
3
use bevy::ecs::component::Component;
4
use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}};
···
10
#[derive(Component)]
11
pub struct VoiceChatMicrophone{
12
stream: Option<Stream>,
13
+
addr: SocketAddr,
14
+
udp: UdpSocket,
15
muted: Arc<Mutex<bool>>,
16
+
last_rms: Arc<RwLock<f32>>,
17
+
gate_level: Arc<RwLock<f32>>
18
}
19
20
impl VoiceChatMicrophone{
21
+
pub fn new( addr: SocketAddr, socket: UdpSocket ) -> Self{
22
Self {
23
stream: None,
24
+
addr,
25
+
udp: socket,
26
muted: Arc::new(Mutex::new(false)), // TODO: Default to muted
27
+
last_rms: Arc::new(RwLock::new(0.0)),
28
+
gate_level: Arc::new(RwLock::new(-65.0))
29
}
30
}
31
···
62
let mut buffer = [0; MONO_20MS];
63
64
let muted = self.muted.clone();
65
66
+
let udp = self.udp.try_clone().unwrap();
67
+
let addr = self.addr.clone();
68
69
for conf in mic.supported_input_configs().unwrap(){
70
println!("{} {:?} {} {:?}", conf.channels(), conf.buffer_size(), conf.sample_format(), conf.with_max_sample_rate());
71
}
72
73
let set_rms = self.last_rms.clone();
74
+
let gate_level = self.gate_level.clone();
75
76
let stream = mic.build_input_stream(
77
&StreamConfig {
···
86
buffer_indx = 0;
87
} else{
88
for i in 0..data.len(){
89
+
if i % 2 == 1{ continue; }
90
91
buffer[buffer_indx] = data[i];
92
buffer_indx += 1;
···
94
if buffer_indx >= MONO_20MS{
95
buffer_indx = 0;
96
97
+
let mut total = 0.0;
98
+
for sample in buffer{ total += (sample as f32).powi(2) }
99
100
+
let rms = 20.0 * ( ( total / buffer.len() as f32 ).sqrt() / i16::MAX as f32 ).log10();
101
+
*set_rms.write().unwrap() = rms;
102
103
+
if rms > *gate_level.read().unwrap(){
104
+
let len = encoder.encode(&buffer, &mut output).unwrap();
105
+
let buf_to_send = output[0..len].to_vec();
106
107
+
let packet = PlayerVoicePacket {
108
+
id: "".into(), // NOTE: I know this kinda seems stupid but it's easier for me to get the player id on the server so imma just make the server fill this in.
109
+
packet: buf_to_send
110
+
};
111
+
112
+
let packet: Vec<u8> = packet.to_buf().into();
113
+
udp.send_to(&packet, addr).unwrap();
114
+
}
115
}
116
}
117
}
···
126
Ok(())
127
}
128
129
+
pub fn get_rms_of_last_packet( &self ) -> ( f32, bool ){
130
+
let rms = *self.last_rms.read().unwrap();
131
+
let gate = *self.gate_level.read().unwrap();
132
+
133
+
( rms, rms > gate )
134
}
135
}
+3
-3
audio/src/voice/mod.rs
+3
-3
audio/src/voice/mod.rs
···
1
-
use std::net::UdpSocket;
2
3
use crate::voice::microphone::VoiceChatMicrophone;
4
5
pub mod decoder;
6
pub mod microphone;
7
8
-
pub fn init_microphone( socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{
9
-
let mut handle = VoiceChatMicrophone::new(socket);
10
handle.start_stream()?;
11
12
Ok(handle)
···
1
+
use std::net::{SocketAddr, UdpSocket};
2
3
use crate::voice::microphone::VoiceChatMicrophone;
4
5
pub mod decoder;
6
pub mod microphone;
7
8
+
pub fn init_microphone( addr: SocketAddr, socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{
9
+
let mut handle = VoiceChatMicrophone::new(addr, socket);
10
handle.start_stream()?;
11
12
Ok(handle)
+2
client/Cargo.toml
+2
client/Cargo.toml
···
10
dotenvy = "0.15.7"
11
felix-net = { path = '../net' }
12
felix-audio = { path = '../audio' }
13
+
felix-assets = { path = '../assets' }
14
tokio = { version = "1.48.0", features = ["full"] }
15
bevy_mod_openxr = "0.4.0"
16
openxr = "0.19.0"
17
bevy_mod_xr = "0.4.0"
18
+
bevy_xr_utils = "0.4.0"
+88
-38
client/src/components/debug_camera.rs
+88
-38
client/src/components/debug_camera.rs
···
1
use std::f32::consts::PI;
2
3
use bevy::{ input::mouse::MouseMotion, prelude::* };
4
-
use bevy_mod_xr::session::XrState;
5
use felix_audio::voice::microphone::VoiceChatMicrophone;
6
7
use crate::net::connection::Connection;
···
21
}
22
}
23
24
pub fn update(
25
mut query: Query<(&mut DebugCamera, &mut Transform)>,
26
-
27
time: Res<Time>,
28
29
keys: Res<ButtonInput<KeyCode>>,
···
37
xr_state: Res<XrState>
38
){
39
let net_manager = networking.single().unwrap();
40
41
-
let mut delta_time = time.delta_secs();
42
-
if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; }
43
44
-
let ( mut debug, mut transform ) = query.single_mut().unwrap();
45
46
-
for ev in mouse_motion.read(){
47
-
if mouse_buttons.pressed(MouseButton::Right){
48
-
debug.pitch -= ev.delta.y * delta_time * 0.1;
49
-
debug.yaw -= ev.delta.x * delta_time * 0.1;
50
}
51
-
}
52
53
-
transform.rotation = Quat::from_euler(EulerRot::YXZ, debug.yaw, debug.pitch, 0.0);
54
55
-
if keys.pressed(KeyCode::KeyW){
56
-
let dir = transform.forward();
57
-
transform.translation += dir * delta_time;
58
-
} else if keys.pressed(KeyCode::KeyS){
59
-
let dir = -transform.forward();
60
-
transform.translation += dir * delta_time;
61
-
}
62
63
-
if keys.pressed(KeyCode::KeyA){
64
-
let dir = transform.left();
65
-
transform.translation += dir * delta_time;
66
-
} else if keys.pressed(KeyCode::KeyD){
67
-
let dir = -transform.left();
68
-
transform.translation += dir * delta_time;
69
-
}
70
71
-
if keys.pressed(KeyCode::KeyE){
72
-
let dir = transform.up();
73
-
transform.translation += dir * delta_time;
74
-
} else if keys.pressed(KeyCode::KeyQ){
75
-
let dir = -transform.up();
76
-
transform.translation += dir * delta_time;
77
}
78
79
let mut remote_rms = "".to_owned();
80
for id in net_manager.get_remote_player_voice_ids(){
81
-
remote_rms += format!("{}: {:.4}\n", id, net_manager.get_remote_player_voice_rms(&id)).as_str();
82
}
83
84
-
let rms = if let Ok(mic) = voice.single(){
85
mic.get_rms_of_last_packet()
86
} else{
87
-
-1.0
88
};
89
90
let ( mut text, _ ) = debug_text.single_mut().unwrap();
91
text.0 = format!(
92
-
"Microphone RMS: {:.4}
93
-
{}Position: {:.2} {:.2} {:.2}
94
-
Rotation: {:.2} {:.2} {:.2} {:.2}
95
XR State: {:#?}",
96
rms,
97
98
remote_rms,
99
···
106
transform.rotation.z,
107
transform.rotation.w,
108
109
-
xr_state.into_inner()
110
);
111
}
112
···
1
use std::f32::consts::PI;
2
3
use bevy::{ input::mouse::MouseMotion, prelude::* };
4
+
use bevy_mod_openxr::{helper_traits::ToQuat, resources::OxrViews};
5
+
use bevy_mod_xr::session::{XrState, XrTrackingRoot};
6
use felix_audio::voice::microphone::VoiceChatMicrophone;
7
8
use crate::net::connection::Connection;
···
22
}
23
}
24
25
+
pub fn vr_locomotion( // TODO: Move locomotion to controllers instead of keyboard
26
+
views: ResMut<OxrViews>,
27
+
mut position_query: Query<&mut Transform, With<XrTrackingRoot>>,
28
+
keys: Res<ButtonInput<KeyCode>>,
29
+
xr_state: Res<XrState>,
30
+
time: Res<Time>
31
+
){
32
+
if *xr_state == XrState::Running{
33
+
let mut delta_time = time.delta_secs();
34
+
if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; }
35
+
36
+
let mut transform = position_query.single_mut().unwrap();
37
+
let view = views.first().unwrap();
38
+
39
+
let cam = view.pose.orientation.to_quat();
40
+
41
+
if keys.pressed(KeyCode::KeyW){
42
+
let mut dir = cam * -Vec3::Z * delta_time;
43
+
dir.y = 0.0;
44
+
45
+
transform.translation += dir;
46
+
} else if keys.pressed(KeyCode::KeyS){
47
+
let mut dir = cam * Vec3::Z * delta_time;
48
+
dir.y = 0.0;
49
+
50
+
transform.translation += dir;
51
+
}
52
+
53
+
if keys.pressed(KeyCode::KeyA){
54
+
let mut dir = cam * -Vec3::X * delta_time;
55
+
dir.y = 0.0;
56
+
57
+
transform.translation += dir;
58
+
} else if keys.pressed(KeyCode::KeyD){
59
+
let mut dir = cam * Vec3::X * delta_time;
60
+
dir.y = 0.0;
61
+
62
+
transform.translation += dir;
63
+
}
64
+
}
65
+
}
66
+
67
pub fn update(
68
mut query: Query<(&mut DebugCamera, &mut Transform)>,
69
time: Res<Time>,
70
71
keys: Res<ButtonInput<KeyCode>>,
···
79
xr_state: Res<XrState>
80
){
81
let net_manager = networking.single().unwrap();
82
+
let xr_state = xr_state.into_inner();
83
84
+
let ( mut debug, mut transform ) = query.single_mut().unwrap();
85
86
+
if *xr_state != XrState::Running{
87
+
let mut delta_time = time.delta_secs();
88
+
if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; }
89
90
+
for ev in mouse_motion.read(){
91
+
if mouse_buttons.pressed(MouseButton::Right){
92
+
debug.pitch -= ev.delta.y * delta_time * 0.1;
93
+
debug.yaw -= ev.delta.x * delta_time * 0.1;
94
+
}
95
}
96
97
+
transform.rotation = Quat::from_euler(EulerRot::YXZ, debug.yaw, debug.pitch, 0.0);
98
99
+
if keys.pressed(KeyCode::KeyW){
100
+
let dir = transform.forward();
101
+
transform.translation += dir * delta_time;
102
+
} else if keys.pressed(KeyCode::KeyS){
103
+
let dir = -transform.forward();
104
+
transform.translation += dir * delta_time;
105
+
}
106
107
+
if keys.pressed(KeyCode::KeyA){
108
+
let dir = transform.left();
109
+
transform.translation += dir * delta_time;
110
+
} else if keys.pressed(KeyCode::KeyD){
111
+
let dir = -transform.left();
112
+
transform.translation += dir * delta_time;
113
+
}
114
115
+
if keys.pressed(KeyCode::KeyE){
116
+
let dir = transform.up();
117
+
transform.translation += dir * delta_time;
118
+
} else if keys.pressed(KeyCode::KeyQ){
119
+
let dir = -transform.up();
120
+
transform.translation += dir * delta_time;
121
+
}
122
}
123
124
let mut remote_rms = "".to_owned();
125
for id in net_manager.get_remote_player_voice_ids(){
126
+
remote_rms += format!(
127
+
"{}: {:.4}db\n",
128
+
id,
129
+
net_manager.get_remote_player_voice_rms(&id)
130
+
).as_str();
131
}
132
133
+
let ( rms, mic_open ) = if let Ok(mic) = voice.single(){
134
mic.get_rms_of_last_packet()
135
} else{
136
+
( -1.0, false )
137
};
138
139
let ( mut text, _ ) = debug_text.single_mut().unwrap();
140
text.0 = format!(
141
+
"Microphone RMS: {:.4}db Open: {}
142
+
{}Position: X: {:.2} Y: {:.2} Z: {:.2}
143
+
Rotation: X: {:.2} Y: {:.2} Z: {:.2} W: {:.2}
144
XR State: {:#?}",
145
rms,
146
+
mic_open,
147
148
remote_rms,
149
···
156
transform.rotation.z,
157
transform.rotation.w,
158
159
+
xr_state
160
);
161
}
162
+37
-26
client/src/main.rs
+37
-26
client/src/main.rs
···
1
use bevy::{app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands, prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin};
2
use bevy_mod_openxr::{add_xr_plugins, resources::OxrSessionConfig};
3
-
use bevy_mod_xr::session::{XrSessionCreated, XrSessionPlugin};
4
use felix_audio::{FelixAudio, voice};
5
-
use openxr::EnvironmentBlendMode;
6
7
use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup};
8
···
12
13
fn main() {
14
if let Err(err) = dotenvy::dotenv(){ println!("[WARN] .ENV failed loading {:#?}", err); }
15
16
-
App::new()
17
-
.add_plugins((
18
add_xr_plugins(
19
DefaultPlugins
20
.build()
21
.disable::<PipelinedRenderingPlugin>(),
22
).set(XrSessionPlugin { auto_handle: true }),
23
-
FelixAudio
24
))
25
.insert_resource(OxrSessionConfig {
26
-
blend_mode_preference: vec![
27
-
EnvironmentBlendMode::ALPHA_BLEND,
28
-
EnvironmentBlendMode::ADDITIVE,
29
-
EnvironmentBlendMode::OPAQUE
30
-
],
31
..Default::default()
32
})
33
-
.add_systems(XrSessionCreated, || { println!("[INFO] Started VR") })
34
-
.add_systems(Startup, setup)
35
-
.add_systems(Startup, move | mut commands: Commands |{
36
-
let ( comp, voice ) = net::handle_net().expect("Network Module Failed");
37
-
commands.spawn(comp);
38
39
-
match voice::init_microphone(voice){
40
-
Ok(voice) => { commands.spawn(voice); },
41
-
Err(err) => println!("[WARN] Failed to start microphone: {}", err)
42
-
}
43
-
})
44
-
.add_systems(Update, debug_camera::update)
45
-
.add_systems(Startup, debug_camera::setup)
46
-
.add_systems(Update, remote_player::update)
47
-
.add_systems(FixedUpdate, network_interface::fixed_update)
48
-
.run();
49
-
}
···
1
+
use std::{env, net::ToSocketAddrs};
2
+
3
use bevy::{app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands, prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin};
4
use bevy_mod_openxr::{add_xr_plugins, resources::OxrSessionConfig};
5
+
use bevy_mod_xr::session::{XrSessionCreated, XrSessionPlugin, XrState};
6
+
use bevy_xr_utils::tracking_utils::TrackingUtilitiesPlugin;
7
use felix_audio::{FelixAudio, voice};
8
9
use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup};
10
···
14
15
fn main() {
16
if let Err(err) = dotenvy::dotenv(){ println!("[WARN] .ENV failed loading {:#?}", err); }
17
+
let try_use_vr = env::var("DONT_USE_VR").is_err();
18
19
+
let mut app = App::new();
20
+
21
+
if try_use_vr{
22
+
app.add_plugins((
23
add_xr_plugins(
24
DefaultPlugins
25
.build()
26
.disable::<PipelinedRenderingPlugin>(),
27
).set(XrSessionPlugin { auto_handle: true }),
28
+
TrackingUtilitiesPlugin
29
))
30
.insert_resource(OxrSessionConfig {
31
..Default::default()
32
})
33
+
.add_systems(XrSessionCreated, || { println!("[INFO] Started VR") });
34
+
} else{
35
+
app
36
+
.add_plugins(DefaultPlugins)
37
+
.insert_resource(XrState::Unavailable);
38
+
}
39
+
40
+
app.add_plugins(FelixAudio)
41
+
.add_systems(Startup, setup)
42
+
.add_systems(Startup, move | mut commands: Commands |{
43
+
let addr = env::var("HOST").unwrap().to_socket_addrs().unwrap().nth(0).unwrap();
44
+
45
+
let ( comp, voice ) = net::handle_net(addr.clone()).expect("Network Module Failed");
46
+
commands.spawn(comp);
47
+
48
+
match voice::init_microphone(addr, voice){
49
+
Ok(voice) => { commands.spawn(voice); },
50
+
Err(err) => println!("[WARN] Failed to start microphone: {}", err)
51
+
}
52
+
})
53
+
.add_systems(Update, debug_camera::update)
54
+
.add_systems(Update, debug_camera::vr_locomotion)
55
+
.add_systems(Startup, debug_camera::setup)
56
+
.add_systems(Update, remote_player::update)
57
+
.add_systems(FixedUpdate, network_interface::fixed_update);
58
59
+
app.run();
60
+
}
+1
-1
client/src/net/connection.rs
+1
-1
client/src/net/connection.rs
+2
-4
client/src/net/mod.rs
+2
-4
client/src/net/mod.rs
···
1
-
use std::{env, net::{TcpStream, ToSocketAddrs, UdpSocket}};
2
3
use bevy::prelude::*;
4
use felix_net::packet::PacketTypes;
···
14
RecvPacket(PacketTypes)
15
}
16
17
-
pub fn handle_net() -> anyhow::Result<( Connection, UdpSocket )>{
18
-
let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap();
19
-
20
let tcp = TcpStream::connect(addr)?;
21
let udp = UdpSocket::bind("0.0.0.0:0")?;
22
···
1
+
use std::net::{SocketAddr, TcpStream, UdpSocket};
2
3
use bevy::prelude::*;
4
use felix_net::packet::PacketTypes;
···
14
RecvPacket(PacketTypes)
15
}
16
17
+
pub fn handle_net( addr: SocketAddr ) -> anyhow::Result<( Connection, UdpSocket )>{
18
let tcp = TcpStream::connect(addr)?;
19
let udp = UdpSocket::bind("0.0.0.0:0")?;
20
+69
-22
client/src/setup.rs
+69
-22
client/src/setup.rs
···
1
use bevy::prelude::*;
2
use felix_audio::FelixAudioListener;
3
4
use crate::components::debug_camera::DebugCamera;
···
9
mut materials: ResMut<Assets<StandardMaterial>>
10
){
11
// TODO: World loading from server
12
13
-
// TODO: World loading format? Could build an asset bundle parser?
14
15
-
// TODO: UI and Menus
16
17
-
commands.spawn((
18
-
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
19
-
MeshMaterial3d(materials.add(Color::WHITE)),
20
-
Transform::from_xyz(5.0, 0.0, 0.0),
21
-
));
22
23
commands.spawn((
24
-
Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
25
-
MeshMaterial3d(materials.add(Color::WHITE)),
26
-
Transform::from_xyz(-5.0, 0.0, 0.0)
27
));
28
29
commands.spawn((
30
-
Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
31
-
MeshMaterial3d(materials.add(Color::WHITE)),
32
-
Transform::from_xyz(0.0, 0.0, 5.0)
33
));
34
35
commands.spawn((
36
-
Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
37
-
MeshMaterial3d(materials.add(Color::WHITE)),
38
-
Transform::from_xyz(0.0, 0.0, -5.0)
39
));
40
41
-
commands.spawn((
42
-
DebugCamera::default(), // TODO: Build a proper player controller
43
-
Camera3d::default(),
44
-
Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
45
-
FelixAudioListener
46
-
));
47
}
···
1
use bevy::prelude::*;
2
+
use bevy_mod_xr::session::XrTracker;
3
+
use bevy_xr_utils::tracking_utils::{XrTrackedLocalFloor, XrTrackedStage, XrTrackedView};
4
+
use felix_assets::{BevyObjectData, BevyObjectLightDataType};
5
use felix_audio::FelixAudioListener;
6
7
use crate::components::debug_camera::DebugCamera;
···
12
mut materials: ResMut<Assets<StandardMaterial>>
13
){
14
// TODO: World loading from server
15
+
// TODO: UI and Menus
16
17
+
// commands.spawn((
18
+
// Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
19
+
// MeshMaterial3d(materials.add(Color::WHITE)),
20
+
// Transform::from_xyz(5.0, 0.0, 0.0),
21
+
// ));
22
23
+
// commands.spawn((
24
+
// Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
25
+
// MeshMaterial3d(materials.add(Color::WHITE)),
26
+
// Transform::from_xyz(-5.0, 0.0, 0.0)
27
+
// ));
28
29
+
// commands.spawn((
30
+
// Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
31
+
// MeshMaterial3d(materials.add(Color::WHITE)),
32
+
// Transform::from_xyz(0.0, 0.0, 5.0)
33
+
// ));
34
+
35
+
// commands.spawn((
36
+
// Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
37
+
// MeshMaterial3d(materials.add(Color::WHITE)),
38
+
// Transform::from_xyz(0.0, 0.0, -5.0)
39
+
// ));
40
41
commands.spawn((
42
+
DebugCamera::default(), // TODO: Build a proper player controller
43
+
Camera3d::default(),
44
+
Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
45
+
FelixAudioListener,
46
+
XrTracker,
47
+
XrTrackedView
48
));
49
50
commands.spawn((
51
+
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
52
+
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 144))),
53
+
Transform::from_xyz(0.0, 0.0, 0.0),
54
+
XrTrackedLocalFloor,
55
+
XrTracker,
56
));
57
58
commands.spawn((
59
+
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
60
+
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 255))),
61
+
Transform::from_xyz(0.0, 0.0, 0.0),
62
+
XrTrackedStage,
63
+
XrTracker,
64
));
65
66
+
let gos = felix_assets::load("/home/phaze/Documents/rindo.flx").unwrap();
67
+
for go in gos{
68
+
match go.data{
69
+
BevyObjectData::Mesh(mesh) => {
70
+
commands.spawn((
71
+
Mesh3d(meshes.add(mesh)),
72
+
MeshMaterial3d(materials.add(Color::WHITE)),
73
+
go.transform
74
+
));
75
+
},
76
+
BevyObjectData::Light(light) => {
77
+
match light.type_{
78
+
BevyObjectLightDataType::Point => {
79
+
commands.spawn((
80
+
PointLight {
81
+
color: light.colour,
82
+
intensity: light.power,
83
+
shadows_enabled: true,
84
+
..Default::default()
85
+
},
86
+
go.transform
87
+
));
88
+
},
89
+
_ => {}
90
+
}
91
+
}
92
+
}
93
+
}
94
}