Compare commits

...

5 Commits

19 changed files with 775 additions and 97 deletions

389
Cargo.lock generated
View File

@ -97,9 +97,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.71"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "arrayref"
@ -312,6 +312,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bit_field"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -515,6 +521,30 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset 0.9.0",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
@ -524,6 +554,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "d3d12"
version = "0.6.0"
@ -598,6 +634,12 @@ dependencies = [
"syn 2.0.26",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "equivalent"
version = "1.0.1"
@ -631,6 +673,22 @@ version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "exr"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1e481eb11a482815d3e9d618db8c42a93207134662873809335a92327440c18"
dependencies = [
"bit_field",
"flume",
"half",
"lebe",
"miniz_oxide",
"rayon-core",
"smallvec",
"zune-inflate",
]
[[package]]
name = "fastrand"
version = "1.9.0"
@ -665,6 +723,19 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"pin-project",
"spin",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
@ -680,6 +751,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futures-channel"
version = "0.3.28"
@ -716,6 +793,12 @@ dependencies = [
"waker-fn",
]
[[package]]
name = "futures-sink"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]]
name = "fxhash"
version = "0.2.1"
@ -732,8 +815,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "gif"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
dependencies = [
"color_quant",
"weezl",
]
[[package]]
@ -847,6 +942,15 @@ dependencies = [
"bitflags",
]
[[package]]
name = "half"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
dependencies = [
"crunchy",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -900,17 +1004,21 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "image"
version = "0.24.6"
version = "0.24.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"exr",
"gif",
"jpeg-decoder",
"num-rational",
"num-rational 0.4.1",
"num-traits",
"png",
"qoi",
"tiff",
]
[[package]]
@ -992,6 +1100,9 @@ name = "jpeg-decoder"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
dependencies = [
"rayon",
]
[[package]]
name = "js-sys"
@ -1028,6 +1139,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lebe"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
version = "0.2.147"
@ -1105,8 +1222,10 @@ dependencies = [
"glam",
"image",
"instant",
"lyra-resource",
"petgraph",
"quote",
"stopwatch",
"syn 2.0.26",
"tobj",
"tracing",
@ -1117,6 +1236,16 @@ dependencies = [
"winit",
]
[[package]]
name = "lyra-resource"
version = "0.0.1"
dependencies = [
"anyhow",
"image",
"thiserror",
"uuid",
]
[[package]]
name = "mach2"
version = "0.4.1"
@ -1159,6 +1288,15 @@ dependencies = [
"autocfg",
]
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "metal"
version = "0.24.0"
@ -1221,6 +1359,15 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
]
[[package]]
name = "ndk"
version = "0.7.0"
@ -1259,7 +1406,7 @@ dependencies = [
"bitflags",
"cfg-if",
"libc",
"memoffset",
"memoffset 0.6.5",
]
[[package]]
@ -1272,7 +1419,7 @@ dependencies = [
"bitflags",
"cfg-if",
"libc",
"memoffset",
"memoffset 0.6.5",
]
[[package]]
@ -1307,6 +1454,42 @@ dependencies = [
"winapi",
]
[[package]]
name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational 0.1.42",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
dependencies = [
"num-integer",
"num-traits",
"rand",
"rustc-serialize",
]
[[package]]
name = "num-complex"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
dependencies = [
"num-traits",
"rustc-serialize",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@ -1317,6 +1500,29 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
"rustc-serialize",
]
[[package]]
name = "num-rational"
version = "0.4.1"
@ -1337,6 +1543,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "num_enum"
version = "0.5.11"
@ -1500,12 +1716,32 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "petgraph"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap 1.9.3",
"indexmap 2.0.0",
]
[[package]]
name = "pin-project"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.26",
]
[[package]]
@ -1591,6 +1827,15 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332cd62e95873ea4f41f3dfd6bbbfc5b52aec892d7e8d534197c4720a0bbbab2"
[[package]]
name = "qoi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
dependencies = [
"bytemuck",
]
[[package]]
name = "quote"
version = "1.0.29"
@ -1600,6 +1845,34 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "range-alloc"
version = "0.1.3"
@ -1612,6 +1885,37 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
@ -1639,6 +1943,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "rustix"
version = "0.37.23"
@ -1771,6 +2081,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "spirv"
version = "0.2.0+1.5.4"
@ -1787,6 +2106,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stopwatch"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d04b5ebc78da44d3a456319d8bc2783e7d8cc7ccbb5cb4dc3f54afbd93bf728"
dependencies = [
"num",
]
[[package]]
name = "strict-num"
version = "0.1.1"
@ -1826,18 +2154,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.43"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42"
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.43"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
@ -1854,6 +2182,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "tiff"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
dependencies = [
"flate2",
"jpeg-decoder",
"weezl",
]
[[package]]
name = "time"
version = "0.3.28"
@ -2034,9 +2373,12 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "uuid"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be"
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
dependencies = [
"getrandom",
]
[[package]]
name = "valuable"
@ -2223,6 +2565,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "weezl"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]]
name = "wgpu"
version = "0.15.1"
@ -2579,3 +2927,12 @@ name = "xml-rs"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336"
[[package]]
name = "zune-inflate"
version = "0.2.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
dependencies = [
"simd-adler32",
]

View File

@ -3,9 +3,14 @@ name = "lyra-engine"
version = "0.0.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = [
"lyra-resource"
]
[dependencies]
lyra-resource = { path = "lyra-resource", version = "0.0.1" }
winit = "0.28.1"
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }
@ -22,7 +27,6 @@ tobj = { version = "3.2.1", features = [
instant = "0.1"
async-trait = "0.1.65"
glam = { version = "0.24.0", features = ["bytemuck"] }
petgraph = "0.6.3"
gilrs-core = "0.5.6"
syn = "2.0.26"
quote = "1.0.29"
@ -31,3 +35,4 @@ atomicell = "0.1.9"
aligned-vec = "0.5.0"
tracing-appender = "0.2.2"
stopwatch = "0.0.7"
petgraph = "0.6.4"

12
lyra-resource/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "lyra-resource"
version = "0.0.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
image = "0.24.7"
thiserror = "1.0.48"
uuid = { version = "1.4.1", features = ["v4"] }

26
lyra-resource/src/lib.rs Normal file
View File

@ -0,0 +1,26 @@
pub mod resource_manager;
pub use resource_manager::*;
pub mod resource;
pub use resource::*;
pub mod texture;
pub use texture::*;
pub mod loader;
pub use loader::*;
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View File

@ -0,0 +1,35 @@
pub mod texture;
use std::{io, sync::Arc, fs::File};
use thiserror::Error;
use crate::resource_manager::ResourceStorage;
#[derive(Error, Debug)]
pub enum LoaderError {
#[error("A malformed path was given: '{0}'")]
InvalidPath(String),
#[error("The loader does not support the extension '{0}'")]
UnsupportedExtension(String),
#[error("IOError: '{0}'")]
IOError(io::Error),
// From is implemented for this field in each loader module
#[error("Decoding error: '{0}'")]
DecodingError(anyhow::Error),
}
impl From<io::Error> for LoaderError {
fn from(value: io::Error) -> Self {
LoaderError::IOError(value)
}
}
pub trait ResourceLoader: Send + Sync {
fn extensions(&self) -> &[&str];
fn does_support_file(&self, path: &str) -> bool;
fn load(&self, path: &str) -> Result<Arc<dyn ResourceStorage>, LoaderError>;
}

View File

@ -0,0 +1,62 @@
use std::{fs::File, sync::Arc, path::Path, ffi::OsStr, io::Read};
use image::ImageError;
use crate::{resource_manager::ResourceStorage, texture::Texture, resource::Resource};
use super::{LoaderError, ResourceLoader};
impl From<ImageError> for LoaderError {
fn from(value: ImageError) -> Self {
LoaderError::DecodingError(anyhow::Error::from(value))
}
}
/// A struct that implements the `ResourceLoader` trait used for loading textures.
#[derive(Default)]
pub struct TextureLoader;
impl ResourceLoader for TextureLoader {
fn extensions(&self) -> &[&str] {
&[
// the extensions of these are the names of the formats
"bmp", "dds", "gif", "ico", "jpeg", "jpg", "png", "qoi", "tga", "tiff", "webp",
// farbfeld
"ff",
// pnm
"pnm", "pbm", "pgm", "ppm", "pam",
]
}
fn does_support_file(&self, path: &str) -> bool {
match Path::new(path).extension().and_then(OsStr::to_str) {
Some(ext) => {
self.extensions().contains(&ext)
},
_ => false,
}
}
fn load(&self, path: &str) -> Result<Arc<dyn ResourceStorage>, LoaderError> {
// check if the file is supported by this loader
if !self.does_support_file(path) {
return Err(LoaderError::UnsupportedExtension(path.to_string()));
}
// read file bytes
let mut file = File::open(path)?;
let mut buf = vec![];
file.read_to_end(&mut buf)?;
// load the image and construct Resource<Texture>
let image = image::load_from_memory(&buf)?;
let texture = Texture {
image,
};
let res = Resource::with_data(path, texture);
Ok(Arc::new(res))
}
}

View File

@ -0,0 +1,29 @@
use std::sync::Arc;
use uuid::Uuid;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ResourceState {
Loading,
Ready,
}
#[derive(Clone)]
pub struct Resource<T: Send + Sync + 'static> {
pub path: String,
pub data: Option<Arc<T>>,
pub uuid: Uuid,
pub state: ResourceState,
}
impl<T: Send + Sync + 'static> Resource<T> {
/// Create the resource with data, its assumed the state is `Ready`
pub fn with_data(path: &str, data: T) -> Self {
Self {
path: path.to_string(),
data: Some(Arc::new(data)),
uuid: Uuid::new_v4(),
state: ResourceState::Ready,
}
}
}

View File

@ -0,0 +1,83 @@
use std::{sync::Arc, collections::{HashMap, hash_map::DefaultHasher}, hash::{Hash, Hasher}, any::Any};
use thiserror::Error;
use crate::{resource::Resource, loader::{ResourceLoader, LoaderError, texture::TextureLoader}};
pub trait ResourceStorage: Send + Sync + Any + 'static {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
/// Implements this trait for anything that fits the type bounds
impl<T: Send + Sync + 'static> ResourceStorage for T {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self.clone()
}
}
#[derive(Error, Debug)]
pub enum RequestError {
#[error("{0}")]
Loader(LoaderError),
#[error("The file extension is unsupported: '{0}'")]
UnsupportedFileExtension(String),
}
impl From<LoaderError> for RequestError {
fn from(value: LoaderError) -> Self {
RequestError::Loader(value)
}
}
#[derive(Default)]
pub struct ResourceManager {
resources: HashMap<String, Arc<dyn ResourceStorage>>,
loaders: Vec<Box<dyn ResourceLoader>>,
}
impl ResourceManager {
pub fn new() -> Self {
Self {
resources: HashMap::new(),
loaders: vec![ Box::new(TextureLoader::default()) ],
}
}
pub fn request<T: Send + Sync + Any + 'static>(&mut self, path: &str) -> Result<Arc<Resource<T>>, RequestError> {
match self.resources.get(&path.to_string()) {
Some(res) => {
let res = res.clone().as_arc_any();
let res = res.downcast::<Resource<T>>().expect("Failure to downcast resource");
Ok(res)
},
None => {
if let Some(loader) = self.loaders.iter()
.find(|l| l.does_support_file(path)) {
// Load the resource and store it
let res = loader.load(path)?;
self.resources.insert(path.to_string(), res.clone());
// convert Arc<dyn ResourceStorage> to Arc<Resource<T>
let res = res.as_arc_any();
let res = res.downcast::<Resource<T>>().expect("Failure to downcast resource");
Ok(res)
} else {
Err(RequestError::UnsupportedFileExtension(path.to_string()))
}
}
}
}
}

View File

@ -0,0 +1,10 @@
use image::{DynamicImage, ImageResult, ImageBuffer, Rgba};
#[derive(Clone)]
pub struct Texture {
pub image: DynamicImage,
}
impl Texture {
}

View File

@ -20,7 +20,13 @@ impl Default for CameraComponent {
}
impl CameraComponent {
pub fn new() -> Self {
pub fn new_3d() -> Self {
Self::default()
}
pub fn new_2d() -> Self {
let mut s = Self::default();
s.mode = CameraProjectionMode::Orthographic;
s
}
}

View File

@ -1,31 +1,29 @@
use std::collections::HashMap;
use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo};
use tracing::warn;
use crate::game::Controls;
pub use edict::*;
pub mod components;
pub mod events;
pub use events::*;
use std::collections::HashMap;
use petgraph::{stable_graph::{StableDiGraph, NodeIndex}, visit::Topo};
use tracing::warn;
/// A trait that represents a simple system
pub trait SimpleSystem {
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
fn setup(&mut self, world: &mut World) -> anyhow::Result<()> {
Ok(())
}
// todo: make async?
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()>;
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()>;
}
impl<S> SimpleSystem for S
where S: FnMut(&mut edict::World) -> anyhow::Result<()>
{
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
self(controls.world)
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self(world)
}
}
@ -44,9 +42,9 @@ impl BatchedSystem {
}
impl SimpleSystem for BatchedSystem {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
for system in self.systems.iter_mut() {
system.execute_mut(controls)?;
system.execute_mut(world)?;
}
Ok(())
@ -122,13 +120,13 @@ impl SystemDispatcher {
true
}
pub(crate) fn execute_systems(&mut self, controls: &mut Controls) {
pub(crate) fn execute_systems(&mut self, world: &mut World) {
let mut topo = Topo::new(&self.graph);
while let Some(nx) = topo.next(&self.graph) {
let node = self.graph.node_weight_mut(nx).unwrap();
match node.system.execute_mut(controls) {
match node.system.execute_mut(world) {
Ok(()) => {},
Err(e) => {
warn!("System execution of {} resulted in an error! '{}'.", node.name, e);
@ -144,8 +142,8 @@ impl SystemDispatcher {
}
impl SimpleSystem for SystemDispatcher {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
self.execute_systems(controls);
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self.execute_systems(world);
Ok(())
}

View File

@ -68,15 +68,11 @@ impl GameLoop {
}
async fn update(&mut self) {
let mut controls = Controls {
world: &mut self.world,
};
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) {
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut self.world) {
error!("Error when executing engine ecs systems: '{}'", e);
}
if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut controls) {
if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut self.world) {
error!("Error when executing user ecs systems: '{}'", e);
}
}
@ -224,9 +220,10 @@ impl GameLoop {
}
pub struct Game {
pub world: Option<edict::World>,
world: Option<edict::World>,
plugins: VecDeque<Box<dyn Plugin>>,
system_dispatcher: Option<SystemDispatcher>,
startup_systems: VecDeque<Box<dyn SimpleSystem>>,
}
impl Default for Game {
@ -235,6 +232,7 @@ impl Default for Game {
world: Some(edict::World::new()),
plugins: VecDeque::new(),
system_dispatcher: Some(SystemDispatcher::new()),
startup_systems: VecDeque::new(),
}
}
}
@ -244,6 +242,13 @@ impl Game {
Self::default()
}
/// Get the world of this game
pub fn world(&mut self) -> &mut edict::World {
// world is always `Some`, so unwrapping is safe
self.world.as_mut().unwrap()
}
/// Add a system to the ecs world
pub fn with_system<S>(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self
where
S: SimpleSystem + 'static
@ -254,7 +259,18 @@ impl Game {
self
}
/// Add a plugin to the game
/// Add a startup system that will be ran right after plugins are setup.
/// They will only be ran once
pub fn with_startup_system<S>(&mut self, system: S) -> &mut Self
where
S: SimpleSystem + 'static
{
self.startup_systems.push_back(Box::new(system));
self
}
/// Add a plugin to the game. These will be executed before the window is initiated and opened
pub fn with_plugin<P>(&mut self, plugin: P) -> &mut Self
where
P: Plugin + 'static
@ -264,12 +280,16 @@ impl Game {
self
}
/// Override the default (empty) world
///
/// This isn't recommended, you should create a startup system and add it to `with_startup_system`
pub fn with_world(&mut self, world: edict::World) -> &mut Self {
self.world = Some(world);
self
}
/// Start the game
pub async fn run(&mut self) {
// init logging
let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout());
@ -286,11 +306,19 @@ impl Game {
plugin.as_ref().setup(self);
}
let mut world = self.world.take().unwrap_or_else(|| edict::World::new());
// run startup systems
while let Some(mut startup) = self.startup_systems.pop_front() {
let startup = startup.as_mut();
startup.setup(&mut world).expect("World returned an error!");
startup.execute_mut(&mut world).expect("World returned an error!");
}
// start winit event loops
let event_loop = EventLoop::new();
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
let world = self.world.take().unwrap_or_else(|| edict::World::new());
let system_dispatcher = self.system_dispatcher.take().unwrap();
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
g_loop.on_init().await;

View File

@ -313,9 +313,7 @@ impl InputSystem {
}
impl SimpleSystem for InputSystem {
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> {
let world = &mut controls.world;
fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> {
let queue = world.get_resource_mut::<EventQueue>()
.map(|q| q.read_events::<InputEvent>()).flatten();

View File

@ -8,17 +8,6 @@ pub mod input;
pub mod castable_any;
pub mod plugin;
use plugin::Plugin;
pub use lyra_resource as assets;
use crate::input::InputPlugin;
/// Default plugins of Lyra. Make sure to have these added to the Game first
#[derive(Default)]
pub struct DefaultPlugins;
impl Plugin for DefaultPlugins {
fn setup(&self, game: &mut game::Game) {
// setup input
InputPlugin::default().setup(game);
}
}
pub use plugin::DefaultPlugins;

View File

@ -1,4 +1,7 @@
use lyra_resource::ResourceManager;
use crate::game::Game;
use crate::input::InputPlugin;
/// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities.
pub trait Plugin {
@ -74,3 +77,24 @@ impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6)
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) }
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) }
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) (C14, 14) }
#[derive(Default)]
pub struct ResourceManagerPlugin;
impl Plugin for ResourceManagerPlugin {
fn setup(&self, game: &mut Game) {
game.world().insert_resource(ResourceManager::new());
}
}
/// Default plugins of Lyra. Make sure to have these added to the Game first
#[derive(Default)]
pub struct DefaultPlugins;
impl Plugin for DefaultPlugins {
fn setup(&self, game: &mut Game) {
// setup input
InputPlugin::default().setup(game);
ResourceManagerPlugin::default().setup(game);
}
}

View File

@ -40,6 +40,7 @@ impl Projection {
pub struct RenderCamera {
view_proj: glam::Mat4,
size: PhysicalSize<u32>,
aspect: f32,
znear: f32,
zfar: f32,
@ -50,6 +51,7 @@ impl RenderCamera {
Self {
view_proj: glam::Mat4::IDENTITY,
size,
aspect: size.width as f32 / size.height as f32,
znear: 0.1,
zfar: 100.0,
@ -61,14 +63,12 @@ impl RenderCamera {
}
pub fn update_view_projection(&mut self, camera: &CameraComponent) -> &glam::Mat4 {
match camera.mode {
CameraProjectionMode::Perspective => {
let position = camera.transform.translation;
let target = camera.transform.rotation * glam::Vec3::new(0.0, 0.0, -1.0);
let target = target.normalize();
/* debug!("Camera rotation: {:?}", rotation);
debug!("Camera position: {:?}", position);
debug!("Camera target: {:?}", target); */
let view = glam::Mat4::look_to_rh(
position,
target,
@ -79,9 +79,23 @@ impl RenderCamera {
self.view_proj = OPENGL_TO_WGPU_MATRIX * proj * view;
&self.view_proj
}
},
CameraProjectionMode::Orthographic => {
let position = camera.transform.translation;
let target = camera.transform.rotation * glam::Vec3::new(0.0, 0.0, -1.0);
let target = target.normalize();
pub fn view_proj(&self) -> &glam::Mat4 {
let ratio_size_per_depth = ((camera.fov.to_radians() / 2.0) * 2.0).atan();
let distance = (target - position).length();
let size_y = ratio_size_per_depth * distance;
let size_x = ratio_size_per_depth * distance * self.aspect;
let proj = glam::Mat4::orthographic_rh_gl(-size_x, size_x, -size_y, size_y, self.znear, self.zfar);
self.view_proj = OPENGL_TO_WGPU_MATRIX * proj;
&self.view_proj
},
}
}
}

View File

@ -1,7 +1,9 @@
use super::texture::Texture;
use std::sync::Arc;
use lyra_resource::{Texture, Resource};
#[derive(Clone)]
pub struct Material {
pub shader_id: u32,
pub texture: Texture,
pub texture: Arc<Resource<Texture>>,
}

View File

@ -462,8 +462,9 @@ impl BasicRenderer {
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh);
let texture_img = &model.material.texture;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, &texture_img.img, 0, None).unwrap();
let model_texture = &model.material.texture;
let image = &model_texture.data.as_ref().unwrap().image;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, image, None).unwrap();
let texture_bind_group_layout =
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {

View File

@ -1,8 +1,9 @@
use std::sync::Arc;
use image::GenericImageView;
use lyra_resource::{Resource, Texture};
#[derive(Clone)]
/* #[derive(Clone)]
pub struct Texture {
texture_id: u32,
pub img: image::DynamicImage,
@ -17,14 +18,13 @@ impl Texture {
img,
})
}
}
} */
#[derive(Clone)]
#[allow(dead_code)]
pub struct RenderTexture {
texture_id: u32,
texture: Arc<wgpu::Texture>,
view: Arc<wgpu::TextureView>,
sampler: Arc<wgpu::Sampler>,
@ -33,12 +33,12 @@ pub struct RenderTexture {
impl RenderTexture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], texture_id: u32, label: &str) -> anyhow::Result<Self> {
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
let img = image::load_from_memory(bytes)?;
Self::from_image(device, queue, &img, texture_id, Some(label))
Self::from_image(device, queue, &img, Some(label))
}
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, texture_id: u32, label: Option<&str>) -> anyhow::Result<Self> {
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result<Self> {
let rgba = img.to_rgba8();
let dimensions = img.dimensions();
@ -90,16 +90,16 @@ impl RenderTexture {
);
Ok(Self {
texture_id,
texture: Arc::new(texture),
view: Arc::new(view),
sampler: Arc::new(sampler),
})
}
pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Texture) {
let rgba = texture.img.to_rgba8();
let dimensions = texture.img.dimensions();
pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Arc<Resource<Texture>>) {
let texture = &texture.data.as_ref().unwrap().image;
let rgba = texture.to_rgba8();
let dimensions = texture.dimensions();
let size = wgpu::Extent3d {
width: dimensions.0,
height: dimensions.1,
@ -162,7 +162,6 @@ impl RenderTexture {
texture: Arc::new(texture),
view: Arc::new(view),
sampler: Arc::new(sampler),
texture_id: 0
}
}