+330
-4
Cargo.lock
+330
-4
Cargo.lock
···
104
104
]
105
105
106
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]]
107
122
name = "alsa"
108
123
version = "0.9.1"
109
124
source = "registry+https://github.com/rust-lang/crates.io-index"
···
135
150
"bitflags 2.10.0",
136
151
"cc",
137
152
"cesu8",
138
-
"jni",
153
+
"jni 0.21.1",
139
154
"jni-sys",
140
155
"libc",
141
156
"log",
···
181
196
dependencies = [
182
197
"num-traits",
183
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"
184
205
185
206
[[package]]
186
207
name = "arrayref"
···
987
1008
checksum = "7ef8e4b7e61dfe7719bb03c884dc270cd46a82efb40f93e9933b990c5c190c59"
988
1009
989
1010
[[package]]
1011
+
name = "bevy_mod_openxr"
1012
+
version = "0.4.0"
1013
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1014
+
checksum = "1ead3d12dc1c364bc8f5d063c8cd82df23a3d6261807abecfbbca70ca3cb2c15"
1015
+
dependencies = [
1016
+
"android_system_properties",
1017
+
"ash",
1018
+
"bevy_app",
1019
+
"bevy_camera",
1020
+
"bevy_derive",
1021
+
"bevy_ecs",
1022
+
"bevy_log",
1023
+
"bevy_math",
1024
+
"bevy_mod_xr",
1025
+
"bevy_platform",
1026
+
"bevy_render",
1027
+
"bevy_transform",
1028
+
"jni 0.20.0",
1029
+
"ndk-context",
1030
+
"openxr",
1031
+
"thiserror 2.0.17",
1032
+
"wgpu",
1033
+
"wgpu-hal",
1034
+
]
1035
+
1036
+
[[package]]
1037
+
name = "bevy_mod_xr"
1038
+
version = "0.4.0"
1039
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1040
+
checksum = "4107b79e3e3b38bc57a7c3fceb465300070b4bc3d2ebd839a9e04468b06cc11c"
1041
+
dependencies = [
1042
+
"bevy_app",
1043
+
"bevy_camera",
1044
+
"bevy_color",
1045
+
"bevy_derive",
1046
+
"bevy_ecs",
1047
+
"bevy_gizmos",
1048
+
"bevy_log",
1049
+
"bevy_math",
1050
+
"bevy_render",
1051
+
"bevy_transform",
1052
+
]
1053
+
1054
+
[[package]]
990
1055
name = "bevy_pbr"
991
1056
version = "0.17.3"
992
1057
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1553
1618
]
1554
1619
1555
1620
[[package]]
1621
+
name = "binrw"
1622
+
version = "0.15.0"
1623
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1624
+
checksum = "81419ff39e6ed10a92a7f125290859776ced35d9a08a665ae40b23e7ca702f30"
1625
+
dependencies = [
1626
+
"array-init",
1627
+
"binrw_derive",
1628
+
"bytemuck",
1629
+
]
1630
+
1631
+
[[package]]
1632
+
name = "binrw_derive"
1633
+
version = "0.15.0"
1634
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1635
+
checksum = "376404e55ec40d0d6f8b4b7df3f87b87954bd987f0cf9a7207ea3b6ea5c9add4"
1636
+
dependencies = [
1637
+
"either",
1638
+
"owo-colors",
1639
+
"proc-macro2",
1640
+
"quote",
1641
+
"syn",
1642
+
]
1643
+
1644
+
[[package]]
1556
1645
name = "bit-set"
1557
1646
version = "0.8.0"
1558
1647
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1631
1720
"futures-io",
1632
1721
"futures-lite",
1633
1722
"piper",
1723
+
]
1724
+
1725
+
[[package]]
1726
+
name = "brotli"
1727
+
version = "3.5.0"
1728
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1729
+
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
1730
+
dependencies = [
1731
+
"alloc-no-stdlib",
1732
+
"alloc-stdlib",
1733
+
"brotli-decompressor",
1734
+
]
1735
+
1736
+
[[package]]
1737
+
name = "brotli-decompressor"
1738
+
version = "2.5.1"
1739
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1740
+
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
1741
+
dependencies = [
1742
+
"alloc-no-stdlib",
1743
+
"alloc-stdlib",
1634
1744
]
1635
1745
1636
1746
[[package]]
···
1976
2086
"core-foundation-sys",
1977
2087
"coreaudio-rs 0.11.3",
1978
2088
"dasp_sample",
1979
-
"jni",
2089
+
"jni 0.21.1",
1980
2090
"js-sys",
1981
2091
"libc",
1982
2092
"mach2",
···
1998
2108
"alsa",
1999
2109
"coreaudio-rs 0.13.0",
2000
2110
"dasp_sample",
2001
-
"jni",
2111
+
"jni 0.21.1",
2002
2112
"js-sys",
2003
2113
"libc",
2004
2114
"mach2",
···
2016
2126
]
2017
2127
2018
2128
[[package]]
2129
+
name = "crc"
2130
+
version = "3.4.0"
2131
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2132
+
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
2133
+
dependencies = [
2134
+
"crc-catalog",
2135
+
]
2136
+
2137
+
[[package]]
2138
+
name = "crc-catalog"
2139
+
version = "2.4.0"
2140
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2141
+
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
2142
+
2143
+
[[package]]
2019
2144
name = "crc32fast"
2020
2145
version = "1.5.0"
2021
2146
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2304
2429
]
2305
2430
2306
2431
[[package]]
2432
+
name = "felix-assets"
2433
+
version = "0.1.0"
2434
+
dependencies = [
2435
+
"anyhow",
2436
+
"bevy",
2437
+
"flate2",
2438
+
"unity-asset",
2439
+
"unity-asset-binary",
2440
+
"unity-asset-decode",
2441
+
]
2442
+
2443
+
[[package]]
2307
2444
name = "felix-audio"
2308
2445
version = "0.1.0"
2309
2446
dependencies = [
···
2322
2459
dependencies = [
2323
2460
"anyhow",
2324
2461
"bevy",
2462
+
"bevy_mod_openxr",
2463
+
"bevy_mod_xr",
2325
2464
"cpal 0.16.0",
2326
2465
"dotenvy",
2466
+
"felix-assets",
2327
2467
"felix-audio",
2328
2468
"felix-net",
2469
+
"openxr",
2329
2470
"tokio",
2330
2471
]
2331
2472
···
2882
3023
2883
3024
[[package]]
2884
3025
name = "jni"
3026
+
version = "0.20.0"
3027
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3028
+
checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
3029
+
dependencies = [
3030
+
"cesu8",
3031
+
"combine",
3032
+
"jni-sys",
3033
+
"log",
3034
+
"thiserror 1.0.69",
3035
+
"walkdir",
3036
+
]
3037
+
3038
+
[[package]]
3039
+
name = "jni"
2885
3040
version = "0.21.1"
2886
3041
source = "registry+https://github.com/rust-lang/crates.io-index"
2887
3042
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
···
3069
3224
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
3070
3225
3071
3226
[[package]]
3227
+
name = "lz4_flex"
3228
+
version = "0.12.0"
3229
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3230
+
checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e"
3231
+
dependencies = [
3232
+
"twox-hash",
3233
+
]
3234
+
3235
+
[[package]]
3236
+
name = "lzma-rs"
3237
+
version = "0.3.0"
3238
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3239
+
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
3240
+
dependencies = [
3241
+
"byteorder",
3242
+
"crc",
3243
+
]
3244
+
3245
+
[[package]]
3072
3246
name = "mach2"
3073
3247
version = "0.4.3"
3074
3248
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3342
3516
]
3343
3517
3344
3518
[[package]]
3519
+
name = "num_cpus"
3520
+
version = "1.17.0"
3521
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3522
+
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
3523
+
dependencies = [
3524
+
"hermit-abi",
3525
+
"libc",
3526
+
]
3527
+
3528
+
[[package]]
3345
3529
name = "num_enum"
3346
3530
version = "0.7.5"
3347
3531
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3657
3841
source = "registry+https://github.com/rust-lang/crates.io-index"
3658
3842
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
3659
3843
dependencies = [
3660
-
"jni",
3844
+
"jni 0.21.1",
3661
3845
"ndk 0.8.0",
3662
3846
"ndk-context",
3663
3847
"num-derive",
···
3700
3884
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
3701
3885
3702
3886
[[package]]
3887
+
name = "openxr"
3888
+
version = "0.19.0"
3889
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3890
+
checksum = "2a2d6934d2508f94fd4cbda6c2a326f111f60ce59fd9136df6d478564397dd40"
3891
+
dependencies = [
3892
+
"libc",
3893
+
"libloading",
3894
+
"ndk-context",
3895
+
"openxr-sys",
3896
+
]
3897
+
3898
+
[[package]]
3899
+
name = "openxr-sys"
3900
+
version = "0.11.0"
3901
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3902
+
checksum = "f10e7e38c47f2175fc39363713b656db899fa0b4a14341029702cbdfa6f44d05"
3903
+
dependencies = [
3904
+
"cmake",
3905
+
"libc",
3906
+
"mint",
3907
+
]
3908
+
3909
+
[[package]]
3703
3910
name = "opus"
3704
3911
version = "0.3.0"
3705
3912
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3735
3942
dependencies = [
3736
3943
"ttf-parser 0.25.1",
3737
3944
]
3945
+
3946
+
[[package]]
3947
+
name = "owo-colors"
3948
+
version = "4.2.3"
3949
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3950
+
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
3738
3951
3739
3952
[[package]]
3740
3953
name = "parking"
···
4316
4529
]
4317
4530
4318
4531
[[package]]
4532
+
name = "serde_bytes"
4533
+
version = "0.11.19"
4534
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4535
+
checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
4536
+
dependencies = [
4537
+
"serde",
4538
+
"serde_core",
4539
+
]
4540
+
4541
+
[[package]]
4319
4542
name = "serde_core"
4320
4543
version = "1.0.228"
4321
4544
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4346
4569
"ryu",
4347
4570
"serde",
4348
4571
"serde_core",
4572
+
]
4573
+
4574
+
[[package]]
4575
+
name = "serde_yaml"
4576
+
version = "0.9.34+deprecated"
4577
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4578
+
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
4579
+
dependencies = [
4580
+
"indexmap",
4581
+
"itoa",
4582
+
"ryu",
4583
+
"serde",
4584
+
"unsafe-libyaml",
4349
4585
]
4350
4586
4351
4587
[[package]]
···
5028
5264
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
5029
5265
5030
5266
[[package]]
5267
+
name = "unity-asset"
5268
+
version = "0.2.0"
5269
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5270
+
checksum = "6705b95fda449527055ff77fe5cff49f774dde7335ed92bc3d048fc74066ebaf"
5271
+
dependencies = [
5272
+
"unity-asset-binary",
5273
+
"unity-asset-core",
5274
+
"unity-asset-yaml",
5275
+
]
5276
+
5277
+
[[package]]
5278
+
name = "unity-asset-binary"
5279
+
version = "0.2.0"
5280
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5281
+
checksum = "d739d1414c1732be1035417f83b1e60f234c7d5eb8abda0ee70d178a58137cb7"
5282
+
dependencies = [
5283
+
"binrw",
5284
+
"brotli",
5285
+
"byteorder",
5286
+
"flate2",
5287
+
"indexmap",
5288
+
"lz4_flex",
5289
+
"lzma-rs",
5290
+
"memmap2",
5291
+
"num_cpus",
5292
+
"once_cell",
5293
+
"regex",
5294
+
"serde",
5295
+
"serde_json",
5296
+
"thiserror 2.0.17",
5297
+
"unity-asset-core",
5298
+
]
5299
+
5300
+
[[package]]
5301
+
name = "unity-asset-core"
5302
+
version = "0.2.0"
5303
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5304
+
checksum = "12903fd47e122b5e7e335fc9cb5540bb35ab0ffe5bb57a7741a8c7be8d361361"
5305
+
dependencies = [
5306
+
"indexmap",
5307
+
"lazy_static",
5308
+
"serde",
5309
+
"serde_bytes",
5310
+
"thiserror 2.0.17",
5311
+
]
5312
+
5313
+
[[package]]
5314
+
name = "unity-asset-decode"
5315
+
version = "0.2.0"
5316
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5317
+
checksum = "9ea6e630cdefde54a88ca4fbae54cf3d3e5ba527fac96b085562da3b3834b77b"
5318
+
dependencies = [
5319
+
"indexmap",
5320
+
"serde",
5321
+
"unity-asset-binary",
5322
+
"unity-asset-core",
5323
+
]
5324
+
5325
+
[[package]]
5326
+
name = "unity-asset-yaml"
5327
+
version = "0.2.0"
5328
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5329
+
checksum = "b991e340c27b1578e657defee9f57de867d853b8f40448fb079d0ee3a5ebc77e"
5330
+
dependencies = [
5331
+
"indexmap",
5332
+
"serde",
5333
+
"serde_yaml",
5334
+
"thiserror 2.0.17",
5335
+
"unity-asset-core",
5336
+
]
5337
+
5338
+
[[package]]
5339
+
name = "unsafe-libyaml"
5340
+
version = "0.2.11"
5341
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5342
+
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
5343
+
5344
+
[[package]]
5031
5345
name = "uuid"
5032
5346
version = "1.19.0"
5033
5347
source = "registry+https://github.com/rust-lang/crates.io-index"
···
5294
5608
"js-sys",
5295
5609
"log",
5296
5610
"naga",
5611
+
"parking_lot",
5297
5612
"portable-atomic",
5298
5613
"profiling",
5299
5614
"raw-window-handle",
5300
5615
"smallvec",
5301
5616
"static_assertions",
5302
5617
"wasm-bindgen",
5618
+
"wasm-bindgen-futures",
5303
5619
"web-sys",
5304
5620
"wgpu-core",
5305
5621
"wgpu-hal",
···
5331
5647
"smallvec",
5332
5648
"thiserror 2.0.17",
5333
5649
"wgpu-core-deps-apple",
5650
+
"wgpu-core-deps-emscripten",
5334
5651
"wgpu-core-deps-wasm",
5335
5652
"wgpu-core-deps-windows-linux-android",
5336
5653
"wgpu-hal",
···
5342
5659
version = "26.0.0"
5343
5660
source = "registry+https://github.com/rust-lang/crates.io-index"
5344
5661
checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf"
5662
+
dependencies = [
5663
+
"wgpu-hal",
5664
+
]
5665
+
5666
+
[[package]]
5667
+
name = "wgpu-core-deps-emscripten"
5668
+
version = "26.0.0"
5669
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5670
+
checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d"
5345
5671
dependencies = [
5346
5672
"wgpu-hal",
5347
5673
]
+4
-1
Cargo.toml
+4
-1
Cargo.toml
+12
assets/Cargo.toml
+12
assets/Cargo.toml
···
1
+
[package]
2
+
name = "felix-assets"
3
+
version = "0.1.0"
4
+
edition = "2024"
5
+
6
+
[dependencies]
7
+
anyhow = "1.0.100"
8
+
unity-asset = "0.2.0"
9
+
unity-asset-binary = "0.2.0"
10
+
unity-asset-decode = { version = "0.2.0", features = [ "mesh" ] }
11
+
bevy = "0.17.3"
12
+
flate2 = "1.1.5"
+87
assets/src/buffer.rs
+87
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_i16(&mut self) -> i16{
31
+
let b = self.get_u8s(2);
32
+
i16::from_le_bytes([ b[0], b[1] ])
33
+
}
34
+
35
+
pub fn get_i32(&mut self) -> i32{
36
+
let b = self.get_u8s(4);
37
+
i32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
38
+
}
39
+
40
+
pub fn get_i64(&mut self) -> i64{
41
+
let b = self.get_u8s(8);
42
+
i64::from_le_bytes([ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] ])
43
+
}
44
+
45
+
pub fn get_u16(&mut self) -> u16{
46
+
let b = self.get_u8s(2);
47
+
u16::from_le_bytes([ b[0], b[1] ])
48
+
}
49
+
50
+
pub fn get_u32(&mut self) -> u32{
51
+
let b = self.get_u8s(4);
52
+
u32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
53
+
}
54
+
55
+
pub fn get_u64(&mut self) -> u64{
56
+
let b = self.get_u8s(8);
57
+
u64::from_le_bytes([ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] ])
58
+
}
59
+
60
+
pub fn get_str(&mut self) -> String{
61
+
let length = self.get_u32();
62
+
let b = self.get_u8s(length as usize);
63
+
64
+
let string = str::from_utf8(&b).unwrap();
65
+
string.to_owned()
66
+
}
67
+
68
+
69
+
pub fn get_vec3(&mut self) -> Vec3{
70
+
Vec3 { x: self.get_f32(), y: self.get_f32(), z: self.get_f32() }
71
+
}
72
+
73
+
pub fn get_quat(&mut self) -> Quat{
74
+
Quat::from_xyzw(self.get_f32(), self.get_f32(), self.get_f32(), self.get_f32())
75
+
}
76
+
77
+
78
+
pub fn get_f32(&mut self) -> f32{
79
+
let b = self.get_u8s(4);
80
+
f32::from_le_bytes([ b[0], b[1], b[2], b[3] ])
81
+
}
82
+
83
+
pub fn get_f64(&mut self) -> f64{
84
+
let b = self.get_u8s(8);
85
+
f64::from_le_bytes([ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] ])
86
+
}
87
+
}
+52
assets/src/felix/mod.rs
+52
assets/src/felix/mod.rs
···
1
+
use std::fs::File;
2
+
3
+
use bevy::{asset::RenderAssetUsages, mesh::{Indices, PrimitiveTopology}, prelude::*, transform::components::Transform};
4
+
use flate2::read::GzDecoder;
5
+
6
+
use crate::{BevyObject, buffer::StreamedBuffer};
7
+
8
+
pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{
9
+
let mut objs = vec![];
10
+
11
+
let decoder = GzDecoder::new(File::open(path).unwrap());
12
+
let mut buf = StreamedBuffer::new(decoder);
13
+
14
+
let obj_count = buf.get_u32();
15
+
16
+
for _ in 0..obj_count{
17
+
let name = buf.get_str();
18
+
let transform = Transform {
19
+
translation: buf.get_vec3(),
20
+
rotation: buf.get_quat(),
21
+
scale: buf.get_vec3()
22
+
};
23
+
24
+
let mut vertices = vec![];
25
+
let mut normals = vec![];
26
+
let mut triangles = vec![];
27
+
28
+
let vertex_count = buf.get_u32();
29
+
for _ in 0..vertex_count{
30
+
vertices.push(buf.get_vec3());
31
+
normals.push(buf.get_vec3());
32
+
}
33
+
34
+
let triangle_count = buf.get_u32();
35
+
for _ in 0..triangle_count{
36
+
triangles.push(buf.get_u32());
37
+
triangles.push(buf.get_u32());
38
+
triangles.push(buf.get_u32());
39
+
}
40
+
41
+
objs.push(BevyObject {
42
+
name,
43
+
transform,
44
+
mesh: Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD)
45
+
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
46
+
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
47
+
.with_inserted_indices(Indices::U32(triangles))
48
+
});
49
+
}
50
+
51
+
Ok(objs)
52
+
}
+16
assets/src/lib.rs
+16
assets/src/lib.rs
···
1
+
use bevy::{mesh::Mesh, transform::components::Transform};
2
+
3
+
mod unity;
4
+
mod felix;
5
+
mod buffer;
6
+
7
+
#[derive(Debug)]
8
+
pub struct BevyObject{
9
+
pub name: String,
10
+
pub transform: Transform,
11
+
pub mesh: Mesh,
12
+
}
13
+
14
+
pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{
15
+
felix::load(path)
16
+
}
+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, 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
+
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
1
use std::{sync::{Arc, Mutex}, thread};
2
2
3
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}};
4
+
use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, sound::static_sound::StaticSoundData, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
5
5
6
6
use crate::{FelixAudioComponent, source::AudioSource};
7
7
···
52
52
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
53
53
input_range: ( 0.0, 20.0 ),
54
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
55
easing: Easing::Linear
61
56
})))
62
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
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}};
2
+
use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}};
3
3
4
4
use crate::{FelixAudioComponent, source::{AudioSource, stream_source::sound_data::StreamAudioSourceSoundData}};
5
5
···
44
44
.with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping {
45
45
input_range: ( 0.0, 20.0 ),
46
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
47
easing: Easing::Linear
53
48
})))
54
49
.with_send(&send_track, Value::FromListenerDistance(Mapping {
+1
-1
audio/src/voice/decoder.rs
+1
-1
audio/src/voice/decoder.rs
···
26
26
27
27
let mut total = 0.0;
28
28
for sample in buffer{ total += sample.powi(2) }
29
-
*set_rms.write().unwrap() = ( total / buffer.len() as f32 ).sqrt();
29
+
*set_rms.write().unwrap() = 20.0 * ( total / buffer.len() as f32 ).sqrt().log10();
30
30
31
31
let mut voice = queue.lock().unwrap();
32
32
for sample in buffer{ voice.push_back(sample); }
+36
-22
audio/src/voice/microphone.rs
+36
-22
audio/src/voice/microphone.rs
···
1
-
use std::{env, net::{ToSocketAddrs, UdpSocket}, sync::{Arc, Mutex, RwLock}};
1
+
use std::{env, net::{SocketAddr, UdpSocket}, sync::{Arc, Mutex, RwLock}};
2
2
3
3
use bevy::ecs::component::Component;
4
4
use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}};
···
10
10
#[derive(Component)]
11
11
pub struct VoiceChatMicrophone{
12
12
stream: Option<Stream>,
13
-
udp: Option<UdpSocket>,
13
+
addr: SocketAddr,
14
+
udp: UdpSocket,
14
15
muted: Arc<Mutex<bool>>,
15
-
last_rms: Arc<RwLock<isize>>
16
+
last_rms: Arc<RwLock<f32>>,
17
+
gate_level: Arc<RwLock<f32>>
16
18
}
17
19
18
20
impl VoiceChatMicrophone{
19
-
pub fn new( socket: UdpSocket ) -> Self{
21
+
pub fn new( addr: SocketAddr, socket: UdpSocket ) -> Self{
20
22
Self {
21
23
stream: None,
22
-
udp: Some(socket),
24
+
addr,
25
+
udp: socket,
23
26
muted: Arc::new(Mutex::new(false)), // TODO: Default to muted
24
-
last_rms: Arc::new(RwLock::new(0))
27
+
last_rms: Arc::new(RwLock::new(0.0)),
28
+
gate_level: Arc::new(RwLock::new(-65.0))
25
29
}
26
30
}
27
31
···
58
62
let mut buffer = [0; MONO_20MS];
59
63
60
64
let muted = self.muted.clone();
61
-
let udp = self.udp.take().unwrap();
62
65
63
-
let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap();
66
+
let udp = self.udp.try_clone().unwrap();
67
+
let addr = self.addr.clone();
64
68
65
69
for conf in mic.supported_input_configs().unwrap(){
66
70
println!("{} {:?} {} {:?}", conf.channels(), conf.buffer_size(), conf.sample_format(), conf.with_max_sample_rate());
67
71
}
68
72
69
73
let set_rms = self.last_rms.clone();
74
+
let gate_level = self.gate_level.clone();
70
75
71
76
let stream = mic.build_input_stream(
72
77
&StreamConfig {
73
-
channels: 1,
78
+
channels: 2,
74
79
buffer_size: BufferSize::Fixed(BUFFER_SIZE as u32),
75
80
sample_rate: SampleRate(SAMPLE_RATE as u32)
76
81
},
···
81
86
buffer_indx = 0;
82
87
} else{
83
88
for i in 0..data.len(){
89
+
if i % 2 == 1{ continue; }
90
+
84
91
buffer[buffer_indx] = data[i];
85
92
buffer_indx += 1;
86
93
87
94
if buffer_indx >= MONO_20MS{
88
95
buffer_indx = 0;
89
96
90
-
let mut total = 0;
91
-
for sample in buffer{ total += (sample as isize).pow(2) }
92
-
*set_rms.write().unwrap() = ( total / buffer.len() as isize ).isqrt();
97
+
let mut total = 0.0;
98
+
for sample in buffer{ total += (sample as f32).powi(2) }
93
99
94
-
let len = encoder.encode(&buffer, &mut output).unwrap();
95
-
let buf_to_send = output[0..len].to_vec();
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();
96
106
97
-
let packet = PlayerVoicePacket {
98
-
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.
99
-
packet: buf_to_send
100
-
};
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
+
};
101
111
102
-
let packet: Vec<u8> = packet.to_buf().into();
103
-
udp.send_to(&packet, addr).unwrap();
112
+
let packet: Vec<u8> = packet.to_buf().into();
113
+
udp.send_to(&packet, addr).unwrap();
114
+
}
104
115
}
105
116
}
106
117
}
···
115
126
Ok(())
116
127
}
117
128
118
-
pub fn get_rms_of_last_packet( &self ) -> f32{
119
-
*self.last_rms.read().unwrap() as f32 / i16::MAX as f32
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 )
120
134
}
121
135
}
+3
-3
audio/src/voice/mod.rs
+3
-3
audio/src/voice/mod.rs
···
1
-
use std::net::UdpSocket;
1
+
use std::net::{SocketAddr, UdpSocket};
2
2
3
3
use crate::voice::microphone::VoiceChatMicrophone;
4
4
5
5
pub mod decoder;
6
6
pub mod microphone;
7
7
8
-
pub fn init_microphone( socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{
9
-
let mut handle = VoiceChatMicrophone::new(socket);
8
+
pub fn init_microphone( addr: SocketAddr, socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{
9
+
let mut handle = VoiceChatMicrophone::new(addr, socket);
10
10
handle.start_stream()?;
11
11
12
12
Ok(handle)
+4
client/Cargo.toml
+4
client/Cargo.toml
+17
-7
client/src/components/debug_camera.rs
+17
-7
client/src/components/debug_camera.rs
···
1
1
use std::f32::consts::PI;
2
2
3
3
use bevy::{ input::mouse::MouseMotion, prelude::* };
4
+
use bevy_mod_xr::session::XrState;
4
5
use felix_audio::voice::microphone::VoiceChatMicrophone;
5
6
6
7
use crate::net::connection::Connection;
···
33
34
mut debug_text: Query<(&mut Text, &DebugText)>,
34
35
voice: Query<&VoiceChatMicrophone>,
35
36
networking: Query<&Connection>,
37
+
xr_state: Res<XrState>
36
38
){
37
39
let net_manager = networking.single().unwrap();
38
40
···
76
78
77
79
let mut remote_rms = "".to_owned();
78
80
for id in net_manager.get_remote_player_voice_ids(){
79
-
remote_rms += format!("{}: {:.4}\n", id, net_manager.get_remote_player_voice_rms(&id)).as_str();
81
+
remote_rms += format!(
82
+
"{}: {:.4}db\n",
83
+
id,
84
+
net_manager.get_remote_player_voice_rms(&id)
85
+
).as_str();
80
86
}
81
87
82
-
let rms = if let Ok(mic) = voice.single(){
88
+
let ( rms, mic_open ) = if let Ok(mic) = voice.single(){
83
89
mic.get_rms_of_last_packet()
84
90
} else{
85
-
-1.0
91
+
( -1.0, false )
86
92
};
87
93
88
94
let ( mut text, _ ) = debug_text.single_mut().unwrap();
89
95
text.0 = format!(
90
-
"Microphone RMS: {:.4}
91
-
{}Position: {:.2} {:.2} {:.2}
92
-
Rotation: {:.2} {:.2} {:.2} {:.2}",
96
+
"Microphone RMS: {:.4}db Open: {}
97
+
{}Position: X: {:.2} Y: {:.2} Z: {:.2}
98
+
Rotation: X: {:.2} Y: {:.2} Z: {:.2} W: {:.2}
99
+
XR State: {:#?}",
93
100
rms,
101
+
mic_open,
94
102
95
103
remote_rms,
96
104
···
101
109
transform.rotation.x,
102
110
transform.rotation.y,
103
111
transform.rotation.z,
104
-
transform.rotation.w
112
+
transform.rotation.w,
113
+
114
+
xr_state.into_inner()
105
115
);
106
116
}
107
117
+24
-4
client/src/main.rs
+24
-4
client/src/main.rs
···
1
-
use bevy::{DefaultPlugins, app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands};
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};
2
6
use felix_audio::{FelixAudio, voice};
7
+
use openxr::EnvironmentBlendMode;
3
8
4
9
use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup};
5
10
···
12
17
13
18
App::new()
14
19
.add_plugins((
15
-
DefaultPlugins,
20
+
add_xr_plugins(
21
+
DefaultPlugins
22
+
.build()
23
+
.disable::<PipelinedRenderingPlugin>(),
24
+
).set(XrSessionPlugin { auto_handle: true }),
16
25
FelixAudio
17
26
))
27
+
.insert_resource(OxrSessionConfig {
28
+
blend_mode_preference: vec![
29
+
EnvironmentBlendMode::ALPHA_BLEND,
30
+
EnvironmentBlendMode::ADDITIVE,
31
+
EnvironmentBlendMode::OPAQUE
32
+
],
33
+
..Default::default()
34
+
})
35
+
.add_systems(XrSessionCreated, || { println!("[INFO] Started VR") })
18
36
.add_systems(Startup, setup)
19
37
.add_systems(Startup, move | mut commands: Commands |{
20
-
let ( comp, voice ) = net::handle_net().expect("Network Module Failed");
38
+
let addr = env::var("HOST").unwrap().to_socket_addrs().unwrap().nth(0).unwrap();
39
+
40
+
let ( comp, voice ) = net::handle_net(addr.clone()).expect("Network Module Failed");
21
41
commands.spawn(comp);
22
42
23
-
match voice::init_microphone(voice){
43
+
match voice::init_microphone(addr, voice){
24
44
Ok(voice) => { commands.spawn(voice); },
25
45
Err(err) => println!("[WARN] Failed to start microphone: {}", err)
26
46
}
+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}};
1
+
use std::net::{SocketAddr, TcpStream, UdpSocket};
2
2
3
3
use bevy::prelude::*;
4
4
use felix_net::packet::PacketTypes;
···
14
14
RecvPacket(PacketTypes)
15
15
}
16
16
17
-
pub fn handle_net() -> anyhow::Result<( Connection, UdpSocket )>{
18
-
let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap();
19
-
17
+
pub fn handle_net( addr: SocketAddr ) -> anyhow::Result<( Connection, UdpSocket )>{
20
18
let tcp = TcpStream::connect(addr)?;
21
19
let udp = UdpSocket::bind("0.0.0.0:0")?;
22
20
+29
-20
client/src/setup.rs
+29
-20
client/src/setup.rs
···
14
14
15
15
// TODO: UI and Menus
16
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
-
));
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
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
-
));
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
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
-
));
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
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
-
));
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
40
41
41
commands.spawn((
42
42
DebugCamera::default(), // TODO: Build a proper player controller
···
44
44
Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
45
45
FelixAudioListener
46
46
));
47
+
48
+
let gos = felix_assets::load("test.flx").unwrap();
49
+
for go in gos{
50
+
commands.spawn((
51
+
Mesh3d(meshes.add(go.mesh)),
52
+
MeshMaterial3d(materials.add(Color::WHITE)),
53
+
go.transform
54
+
));
55
+
}
47
56
}