add audio
This commit is contained in:
parent
e0fccbae6b
commit
79a0768d8e
324
Cargo.lock
generated
324
Cargo.lock
generated
@ -31,12 +31,43 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alsa"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||||
|
dependencies = [
|
||||||
|
"alsa-sys",
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alsa-sys"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-activity"
|
name = "android-activity"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -51,7 +82,7 @@ dependencies = [
|
|||||||
"jni-sys",
|
"jni-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk 0.9.0",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys 0.6.0+11769913",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
@ -112,6 +143,24 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.72.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash 2.1.1",
|
||||||
|
"shlex",
|
||||||
|
"syn 2.0.114",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -220,6 +269,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -238,6 +296,17 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading 0.8.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -338,6 +407,49 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coreaudio-rs"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"coreaudio-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coreaudio-sys"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpal"
|
||||||
|
version = "0.15.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
|
||||||
|
dependencies = [
|
||||||
|
"alsa",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"coreaudio-rs",
|
||||||
|
"dasp_sample",
|
||||||
|
"jni",
|
||||||
|
"js-sys",
|
||||||
|
"libc",
|
||||||
|
"mach2",
|
||||||
|
"ndk 0.8.0",
|
||||||
|
"ndk-context",
|
||||||
|
"oboe",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"windows 0.54.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.21"
|
version = "0.8.21"
|
||||||
@ -361,6 +473,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dasp_sample"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -388,6 +506,12 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -401,7 +525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -470,6 +594,12 @@ dependencies = [
|
|||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@ -520,7 +650,7 @@ dependencies = [
|
|||||||
"presser",
|
"presser",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winapi",
|
"winapi",
|
||||||
"windows",
|
"windows 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -590,8 +720,10 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
|||||||
name = "host_desktop"
|
name = "host_desktop"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cpal",
|
||||||
"pixels",
|
"pixels",
|
||||||
"prometeu-core",
|
"prometeu-core",
|
||||||
|
"ringbuf",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -605,6 +737,15 @@ dependencies = [
|
|||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
@ -728,6 +869,15 @@ version = "0.4.29"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach2"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@ -767,6 +917,12 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "0.19.2"
|
version = "0.19.2"
|
||||||
@ -780,13 +936,27 @@ dependencies = [
|
|||||||
"indexmap",
|
"indexmap",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rustc-hash",
|
"rustc-hash 1.1.0",
|
||||||
"spirv",
|
"spirv",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndk"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"jni-sys",
|
||||||
|
"log",
|
||||||
|
"ndk-sys 0.5.0+25.2.9519653",
|
||||||
|
"num_enum",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -826,6 +996,27 @@ dependencies = [
|
|||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.114",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@ -1079,6 +1270,29 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oboe"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
|
||||||
|
dependencies = [
|
||||||
|
"jni",
|
||||||
|
"ndk 0.8.0",
|
||||||
|
"ndk-context",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"oboe-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oboe-sys"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
@ -1205,6 +1419,21 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
|
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic-util"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||||
|
dependencies = [
|
||||||
|
"portable-atomic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "presser"
|
name = "presser"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -1302,18 +1531,64 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renderdoc-sys"
|
name = "renderdoc-sys"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ringbuf"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe47b720588c8702e34b5979cb3271a8b1842c7cb6f57408efa70c779363488c"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"portable-atomic",
|
||||||
|
"portable-atomic-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
@ -1337,7 +1612,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.11.0",
|
"linux-raw-sys 0.11.0",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1915,7 +2190,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"profiling",
|
"profiling",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"rustc-hash",
|
"rustc-hash 1.1.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
@ -1959,7 +2234,7 @@ dependencies = [
|
|||||||
"range-alloc",
|
"range-alloc",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"renderdoc-sys",
|
"renderdoc-sys",
|
||||||
"rustc-hash",
|
"rustc-hash 1.1.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@ -2017,7 +2292,7 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2032,7 +2307,17 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core",
|
"windows-core 0.52.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.54.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.54.0",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2045,12 +2330,31 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.54.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
@ -2230,7 +2534,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"ndk",
|
"ndk 0.9.0",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
|||||||
@ -1,14 +1,22 @@
|
|||||||
use crate::model::Color;
|
use crate::model::Color;
|
||||||
use crate::peripherals::{Gfx, InputSignals, Pad, Touch};
|
use crate::peripherals::{Gfx, InputSignals, Pad, Touch, Audio, LoopMode};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crate::model::Sample;
|
||||||
|
|
||||||
/// PROMETEU "hardware lógico" (v0).
|
/// PROMETEU "hardware lógico" (v0).
|
||||||
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
|
/// O Host alimenta INPUT SIGNALS e chama `step_frame()` em 60Hz.
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub gfx: Gfx,
|
pub gfx: Gfx,
|
||||||
|
pub audio: Audio,
|
||||||
pub pad: Pad,
|
pub pad: Pad,
|
||||||
pub touch: Touch,
|
pub touch: Touch,
|
||||||
pub frame_index: u64,
|
pub frame_index: u64,
|
||||||
pub last_frame_cpu_time_us: u64,
|
pub last_frame_cpu_time_us: u64,
|
||||||
|
|
||||||
|
// Assets de exemplo
|
||||||
|
pub sample_square: Option<Arc<Sample>>,
|
||||||
|
pub sample_kick: Option<Arc<Sample>>,
|
||||||
|
pub sample_snare: Option<Arc<Sample>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
@ -18,10 +26,14 @@ impl Machine {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
gfx: Gfx::new(Self::W, Self::H),
|
gfx: Gfx::new(Self::W, Self::H),
|
||||||
|
audio: Audio::new(),
|
||||||
pad: Pad::default(),
|
pad: Pad::default(),
|
||||||
touch: Touch::default(),
|
touch: Touch::default(),
|
||||||
frame_index: 0,
|
frame_index: 0,
|
||||||
last_frame_cpu_time_us: 0,
|
last_frame_cpu_time_us: 0,
|
||||||
|
sample_square: None,
|
||||||
|
sample_kick: None,
|
||||||
|
sample_snare: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +52,11 @@ impl Machine {
|
|||||||
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
pub fn begin_frame(&mut self, signals: &InputSignals) {
|
||||||
self.frame_index += 1;
|
self.frame_index += 1;
|
||||||
|
|
||||||
|
// Limpa comandos de áudio do frame anterior.
|
||||||
|
// Nota: O Host deve consumir esses comandos ANTES ou DURANTE o step_frame se quiser processá-los.
|
||||||
|
// Como o Host atual consome logo após o step_frame, limpar aqui no início do PRÓXIMO frame está correto.
|
||||||
|
self.audio.clear_commands();
|
||||||
|
|
||||||
// Flags transitórias do TOUCH devem durar 1 frame.
|
// Flags transitórias do TOUCH devem durar 1 frame.
|
||||||
self.touch.begin_frame(signals);
|
self.touch.begin_frame(signals);
|
||||||
|
|
||||||
@ -178,6 +195,91 @@ impl Machine {
|
|||||||
// Se soltar o Start, podemos pausar algo futuramente
|
// Se soltar o Start, podemos pausar algo futuramente
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- DEMO DE ÁUDIO ---
|
||||||
|
// Inicializa assets de áudio se não existirem
|
||||||
|
if self.sample_square.is_none() {
|
||||||
|
// 1. Onda Quadrada com Loop (Instrumento)
|
||||||
|
let freq = 440.0;
|
||||||
|
let sample_rate = 44100;
|
||||||
|
let period = (sample_rate as f32 / freq) as usize;
|
||||||
|
let mut data = Vec::with_capacity(period);
|
||||||
|
for i in 0..period {
|
||||||
|
data.push(if i < period / 2 { 4000 } else { -4000 });
|
||||||
|
}
|
||||||
|
self.sample_square = Some(Arc::new(Sample::new(sample_rate, data).with_loop(0, period as u32)));
|
||||||
|
|
||||||
|
// 2. "Kick" simples (Pitch descent)
|
||||||
|
let mut kick_data = Vec::new();
|
||||||
|
for i in 0..4000 {
|
||||||
|
let t = i as f32 / 4000.0;
|
||||||
|
let f = 100.0 * (1.0 - t * 0.9);
|
||||||
|
let val = (i as f32 * f * 2.0 * std::f32::consts::PI / 44100.0).sin();
|
||||||
|
kick_data.push((val * 12000.0 * (1.0 - t)) as i16);
|
||||||
|
}
|
||||||
|
self.sample_kick = Some(Arc::new(Sample::new(44100, kick_data)));
|
||||||
|
|
||||||
|
// 3. "Snare" simples (White noise)
|
||||||
|
let mut snare_data = Vec::new();
|
||||||
|
for i in 0..3000 {
|
||||||
|
let t = i as f32 / 3000.0;
|
||||||
|
let noise = Self::rand_f32(i as u32) * 2.0 - 1.0;
|
||||||
|
snare_data.push((noise * 8000.0 * (1.0 - t)) as i16);
|
||||||
|
}
|
||||||
|
self.sample_snare = Some(Arc::new(Sample::new(44100, snare_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SEQUENCER SIMPLES (60Hz) ---
|
||||||
|
let bpm = 125;
|
||||||
|
let frames_per_beat = (60 * 60) / bpm;
|
||||||
|
let frames_per_step = frames_per_beat / 4; // 16th notes
|
||||||
|
|
||||||
|
let step = (self.frame_index / frames_per_step) % 16;
|
||||||
|
let is_new_step = self.frame_index % frames_per_step == 0;
|
||||||
|
|
||||||
|
if is_new_step {
|
||||||
|
// Bassline (Square)
|
||||||
|
// Notas: C-2, C-2, Eb2, F-2, C-2, C-2, G-2, Bb2...
|
||||||
|
let melody = [
|
||||||
|
36, 36, 39, 41,
|
||||||
|
36, 36, 43, 46,
|
||||||
|
36, 36, 39, 41,
|
||||||
|
34, 35, 36, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
let note = melody[step as usize];
|
||||||
|
if note > 0 {
|
||||||
|
// Cálculo de pitch otimizado (tabela simples ou aproximação rápida se necessário,
|
||||||
|
// mas powf uma vez por step está ok. O problema é se fosse todo frame)
|
||||||
|
let freq = 440.0 * 2.0f64.powf((note as f64 - 69.0) / 12.0);
|
||||||
|
let pitch = freq / 440.0;
|
||||||
|
if let Some(s) = &self.sample_square {
|
||||||
|
self.audio.play(s.clone(), 0, 160, 100, pitch, 0, LoopMode::On);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drums
|
||||||
|
let kick_pattern = 0b0101100100011001u16; // Invertido para facilitar bitshift
|
||||||
|
let snare_pattern = 0b0001000000001000u16;
|
||||||
|
|
||||||
|
if (kick_pattern >> step) & 1 == 1 {
|
||||||
|
if let Some(s) = &self.sample_kick {
|
||||||
|
self.audio.play(s.clone(), 1, 255, 127, 1.0, 1, LoopMode::Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (snare_pattern >> step) & 1 == 1 {
|
||||||
|
if let Some(s) = &self.sample_snare {
|
||||||
|
self.audio.play(s.clone(), 2, 140, 150, 1.0, 1, LoopMode::Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toca um "beep" extra se apertar A (mantendo interatividade)
|
||||||
|
if self.pad.a.pressed {
|
||||||
|
if let Some(s) = &self.sample_square {
|
||||||
|
self.audio.play(s.clone(), 3, 255, 60, 2.0, 10, LoopMode::Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Post-FX Fade Pulsante
|
// Post-FX Fade Pulsante
|
||||||
let pulse = (self.frame_index / 4) % 64;
|
let pulse = (self.frame_index / 4) % 64;
|
||||||
let level = if pulse > 31 { 63 - pulse } else { pulse };
|
let level = if pulse > 31 { 63 - pulse } else { pulse };
|
||||||
@ -190,4 +292,15 @@ impl Machine {
|
|||||||
pub fn end_frame(&mut self) {
|
pub fn end_frame(&mut self) {
|
||||||
self.gfx.present();
|
self.gfx.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper para noise determinístico
|
||||||
|
fn rand_f32(seed: u32) -> f32 {
|
||||||
|
let mut x = seed.wrapping_add(0x9E3779B9);
|
||||||
|
x = x ^ (x >> 16);
|
||||||
|
x = x.wrapping_mul(0x85EBCA6B);
|
||||||
|
x = x ^ (x >> 13);
|
||||||
|
x = x.wrapping_mul(0xC2B2AE35);
|
||||||
|
x = x ^ (x >> 16);
|
||||||
|
(x as f32) / (u32::MAX as f32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ mod tile;
|
|||||||
mod tile_layer;
|
mod tile_layer;
|
||||||
mod tile_bank;
|
mod tile_bank;
|
||||||
mod sprite;
|
mod sprite;
|
||||||
|
mod sample;
|
||||||
|
|
||||||
pub use button::Button;
|
pub use button::Button;
|
||||||
pub use color::Color;
|
pub use color::Color;
|
||||||
@ -11,3 +12,4 @@ pub use tile::Tile;
|
|||||||
pub use tile_bank::{TileBank, TileSize};
|
pub use tile_bank::{TileBank, TileSize};
|
||||||
pub use tile_layer::{HudTileLayer, ScrollableTileLayer, TileMap};
|
pub use tile_layer::{HudTileLayer, ScrollableTileLayer, TileMap};
|
||||||
pub use sprite::Sprite;
|
pub use sprite::Sprite;
|
||||||
|
pub use sample::Sample;
|
||||||
|
|||||||
27
crates/core/src/model/sample.rs
Normal file
27
crates/core/src/model/sample.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
pub struct Sample {
|
||||||
|
pub sample_rate: u32,
|
||||||
|
pub data: Vec<i16>,
|
||||||
|
pub loop_start: Option<u32>,
|
||||||
|
pub loop_end: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sample {
|
||||||
|
pub fn new(sample_rate: u32, data: Vec<i16>) -> Self {
|
||||||
|
Self {
|
||||||
|
sample_rate,
|
||||||
|
data,
|
||||||
|
loop_start: None,
|
||||||
|
loop_end: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_loop(mut self, start: u32, end: u32) -> Self {
|
||||||
|
self.loop_start = Some(start);
|
||||||
|
self.loop_end = Some(end);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frames_len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
127
crates/core/src/peripherals/audio.rs
Normal file
127
crates/core/src/peripherals/audio.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use crate::model::Sample;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub const MAX_CHANNELS: usize = 16;
|
||||||
|
pub const OUTPUT_SAMPLE_RATE: u32 = 48000;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum LoopMode {
|
||||||
|
Off,
|
||||||
|
On,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Channel {
|
||||||
|
pub sample: Option<Arc<Sample>>,
|
||||||
|
pub pos: f64,
|
||||||
|
pub pitch: f64,
|
||||||
|
pub volume: u8, // 0..255
|
||||||
|
pub pan: u8, // 0..255
|
||||||
|
pub loop_mode: LoopMode,
|
||||||
|
pub priority: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Channel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sample: None,
|
||||||
|
pos: 0.0,
|
||||||
|
pitch: 1.0,
|
||||||
|
volume: 255,
|
||||||
|
pan: 127,
|
||||||
|
loop_mode: LoopMode::Off,
|
||||||
|
priority: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AudioCommand {
|
||||||
|
Play {
|
||||||
|
sample: Arc<Sample>,
|
||||||
|
voice_id: usize,
|
||||||
|
volume: u8,
|
||||||
|
pan: u8,
|
||||||
|
pitch: f64,
|
||||||
|
priority: u8,
|
||||||
|
loop_mode: LoopMode,
|
||||||
|
},
|
||||||
|
Stop {
|
||||||
|
voice_id: usize,
|
||||||
|
},
|
||||||
|
SetVolume {
|
||||||
|
voice_id: usize,
|
||||||
|
volume: u8,
|
||||||
|
},
|
||||||
|
SetPan {
|
||||||
|
voice_id: usize,
|
||||||
|
pan: u8,
|
||||||
|
},
|
||||||
|
SetPitch {
|
||||||
|
voice_id: usize,
|
||||||
|
pitch: f64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Audio {
|
||||||
|
pub voices: [Channel; MAX_CHANNELS],
|
||||||
|
pub commands: Vec<AudioCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Audio {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
voices: Default::default(),
|
||||||
|
commands: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(&mut self, sample: Arc<Sample>, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.commands.push(AudioCommand::Play {
|
||||||
|
sample,
|
||||||
|
voice_id,
|
||||||
|
volume,
|
||||||
|
pan,
|
||||||
|
pitch,
|
||||||
|
priority,
|
||||||
|
loop_mode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self, voice_id: usize) {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.commands.push(AudioCommand::Stop { voice_id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_volume(&mut self, voice_id: usize, volume: u8) {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.commands.push(AudioCommand::SetVolume { voice_id, volume });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pan(&mut self, voice_id: usize, pan: u8) {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.commands.push(AudioCommand::SetPan { voice_id, pan });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pitch(&mut self, voice_id: usize, pitch: f64) {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.commands.push(AudioCommand::SetPitch { voice_id, pitch });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_playing(&self, voice_id: usize) -> bool {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id].sample.is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Limpa a fila de comandos. O Host deve consumir isso a cada frame.
|
||||||
|
pub fn clear_commands(&mut self) {
|
||||||
|
self.commands.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,6 +30,9 @@ pub struct Gfx {
|
|||||||
pub scene_fade_color: Color,
|
pub scene_fade_color: Color,
|
||||||
pub hud_fade_level: u8, // 0..31
|
pub hud_fade_level: u8, // 0..31
|
||||||
pub hud_fade_color: Color,
|
pub hud_fade_color: Color,
|
||||||
|
|
||||||
|
// Cache de prioridades para evitar alocações por frame
|
||||||
|
priority_buckets: [Vec<usize>; 5],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gfx {
|
impl Gfx {
|
||||||
@ -65,6 +68,13 @@ impl Gfx {
|
|||||||
scene_fade_color: Color::BLACK,
|
scene_fade_color: Color::BLACK,
|
||||||
hud_fade_level: 31,
|
hud_fade_level: 31,
|
||||||
hud_fade_color: Color::BLACK,
|
hud_fade_color: Color::BLACK,
|
||||||
|
priority_buckets: [
|
||||||
|
Vec::with_capacity(128),
|
||||||
|
Vec::with_capacity(128),
|
||||||
|
Vec::with_capacity(128),
|
||||||
|
Vec::with_capacity(128),
|
||||||
|
Vec::with_capacity(128),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,33 +135,29 @@ impl Gfx {
|
|||||||
/// Segue a ordem de prioridade do manual (Capítulo 4.11).
|
/// Segue a ordem de prioridade do manual (Capítulo 4.11).
|
||||||
pub fn render_all(&mut self) {
|
pub fn render_all(&mut self) {
|
||||||
// 0. Fase de Preparação: Organiza quem deve ser desenhado em cada camada
|
// 0. Fase de Preparação: Organiza quem deve ser desenhado em cada camada
|
||||||
// Criamos listas de índices para evitar percorrer os 512 sprites 5 vezes
|
// Limpa os buckets sem desalocar memória
|
||||||
let mut priority_buckets: [Vec<usize>; 5] = [
|
for bucket in self.priority_buckets.iter_mut() {
|
||||||
Vec::with_capacity(128),
|
bucket.clear();
|
||||||
Vec::with_capacity(128),
|
}
|
||||||
Vec::with_capacity(128),
|
|
||||||
Vec::with_capacity(128),
|
|
||||||
Vec::with_capacity(128),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (idx, sprite) in self.sprites.iter().enumerate() {
|
for (idx, sprite) in self.sprites.iter().enumerate() {
|
||||||
if sprite.active && sprite.priority < 5 {
|
if sprite.active && sprite.priority < 5 {
|
||||||
priority_buckets[sprite.priority as usize].push(idx);
|
self.priority_buckets[sprite.priority as usize].push(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Sprites de prioridade 0 (Atrás da Layer 0 - o fundo do fundo)
|
// 1. Sprites de prioridade 0 (Atrás da Layer 0 - o fundo do fundo)
|
||||||
self.draw_bucket(&priority_buckets[0]);
|
Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[0], &self.sprites, &self.banks);
|
||||||
|
|
||||||
for i in 0..self.layers.len() {
|
for i in 0..self.layers.len() {
|
||||||
// 2. Layers de jogo (0 a 3)
|
// 2. Layers de jogo (0 a 3)
|
||||||
self.render_layer(i);
|
let bank_id = self.layers[i].bank_id as usize;
|
||||||
|
if let Some(Some(bank)) = self.banks.get(bank_id) {
|
||||||
|
Self::draw_tile_map(&mut self.back, self.w, self.h, &self.layers[i].map, bank, self.layers[i].scroll_x, self.layers[i].scroll_y);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Sprites de acordo com prioridade
|
// 3. Sprites de acordo com prioridade
|
||||||
// i=0 desenha sprites priority 1 (sobre layer 0)
|
Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[i + 1], &self.sprites, &self.banks);
|
||||||
// i=1 desenha sprites priority 2 (sobre layer 1)
|
|
||||||
// i=2 desenha sprites priority 3 (sobre layer 2)
|
|
||||||
// i=3 desenha sprites priority 4 (sobre layer 3 - à frente de tudo)
|
|
||||||
self.draw_bucket(&priority_buckets[i + 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Aplica Scene Fade (Afeta tudo desenhado até agora)
|
// 4. Aplica Scene Fade (Afeta tudo desenhado até agora)
|
||||||
@ -262,15 +268,20 @@ impl Gfx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_bucket(&mut self, bucket: &[usize]) {
|
fn draw_bucket_on_buffer(
|
||||||
|
back: &mut [u16],
|
||||||
|
screen_w: usize,
|
||||||
|
screen_h: usize,
|
||||||
|
bucket: &[usize],
|
||||||
|
sprites: &[Sprite],
|
||||||
|
banks: &[Option<TileBank>],
|
||||||
|
) {
|
||||||
for &idx in bucket {
|
for &idx in bucket {
|
||||||
let sprite = &self.sprites[idx];
|
let s = &sprites[idx];
|
||||||
let bank = match self.banks.get(sprite.bank_id as usize) {
|
let bank_id = s.bank_id as usize;
|
||||||
Some(Some(b)) => b,
|
if let Some(Some(bank)) = banks.get(bank_id) {
|
||||||
_ => continue,
|
Self::draw_sprite_pixel_by_pixel(back, screen_w, screen_h, s, bank);
|
||||||
};
|
}
|
||||||
|
|
||||||
Self::draw_sprite_pixel_by_pixel(&mut self.back, self.w, self.h, sprite, bank);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,11 @@ mod gfx;
|
|||||||
mod pad;
|
mod pad;
|
||||||
mod touch;
|
mod touch;
|
||||||
mod input_signal;
|
mod input_signal;
|
||||||
|
mod audio;
|
||||||
|
|
||||||
pub use gfx::Gfx;
|
pub use gfx::Gfx;
|
||||||
pub use gfx::BlendMode;
|
pub use gfx::BlendMode;
|
||||||
pub use input_signal::InputSignals;
|
pub use input_signal::InputSignals;
|
||||||
pub use pad::Pad;
|
pub use pad::Pad;
|
||||||
pub use touch::Touch;
|
pub use touch::Touch;
|
||||||
|
pub use audio::{Audio, Channel, AudioCommand, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE};
|
||||||
|
|||||||
@ -6,4 +6,6 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
prometeu-core = { path = "../core" }
|
prometeu-core = { path = "../core" }
|
||||||
winit = "0.30.12"
|
winit = "0.30.12"
|
||||||
pixels = "0.15.0"
|
pixels = "0.15.0"
|
||||||
|
cpal = "0.15.3"
|
||||||
|
ringbuf = "0.4.7"
|
||||||
132
crates/host_desktop/src/audio_mixer.rs
Normal file
132
crates/host_desktop/src/audio_mixer.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use prometeu_core::peripherals::{AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE};
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub struct AudioMixer {
|
||||||
|
voices: [Channel; MAX_CHANNELS],
|
||||||
|
pub last_processing_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioMixer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
voices: Default::default(),
|
||||||
|
last_processing_time: Duration::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_command(&mut self, cmd: AudioCommand) {
|
||||||
|
match cmd {
|
||||||
|
AudioCommand::Play {
|
||||||
|
sample,
|
||||||
|
voice_id,
|
||||||
|
volume,
|
||||||
|
pan,
|
||||||
|
pitch,
|
||||||
|
priority,
|
||||||
|
loop_mode,
|
||||||
|
} => {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id] = Channel {
|
||||||
|
sample: Some(sample),
|
||||||
|
pos: 0.0,
|
||||||
|
pitch,
|
||||||
|
volume,
|
||||||
|
pan,
|
||||||
|
loop_mode,
|
||||||
|
priority,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AudioCommand::Stop { voice_id } => {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id].sample = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AudioCommand::SetVolume { voice_id, volume } => {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id].volume = volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AudioCommand::SetPan { voice_id, pan } => {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id].pan = pan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AudioCommand::SetPitch { voice_id, pitch } => {
|
||||||
|
if voice_id < MAX_CHANNELS {
|
||||||
|
self.voices[voice_id].pitch = pitch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_buffer(&mut self, buffer: &mut [f32]) {
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
// Zera o buffer (estéreo)
|
||||||
|
for sample in buffer.iter_mut() {
|
||||||
|
*sample = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for voice in self.voices.iter_mut() {
|
||||||
|
let sample_data = match &voice.sample {
|
||||||
|
Some(s) => s,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let pitch_ratio = sample_data.sample_rate as f64 / OUTPUT_SAMPLE_RATE as f64;
|
||||||
|
let step = voice.pitch * pitch_ratio;
|
||||||
|
|
||||||
|
let vol_f = voice.volume as f32 / 255.0;
|
||||||
|
let pan_f = voice.pan as f32 / 255.0;
|
||||||
|
let vol_l = vol_f * (1.0 - pan_f).sqrt();
|
||||||
|
let vol_r = vol_f * pan_f.sqrt();
|
||||||
|
|
||||||
|
for frame in buffer.chunks_exact_mut(2) {
|
||||||
|
let pos_int = voice.pos as usize;
|
||||||
|
let pos_fract = voice.pos - pos_int as f64;
|
||||||
|
|
||||||
|
if pos_int >= sample_data.data.len() {
|
||||||
|
voice.sample = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolação Linear
|
||||||
|
let s1 = sample_data.data[pos_int] as f32 / 32768.0;
|
||||||
|
let s2 = if pos_int + 1 < sample_data.data.len() {
|
||||||
|
sample_data.data[pos_int + 1] as f32 / 32768.0
|
||||||
|
} else if voice.loop_mode == LoopMode::On {
|
||||||
|
let loop_start = sample_data.loop_start.unwrap_or(0) as usize;
|
||||||
|
sample_data.data[loop_start] as f32 / 32768.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
let sample_val = s1 + (s2 - s1) * pos_fract as f32;
|
||||||
|
|
||||||
|
frame[0] += sample_val * vol_l;
|
||||||
|
frame[1] += sample_val * vol_r;
|
||||||
|
|
||||||
|
voice.pos += step;
|
||||||
|
|
||||||
|
let end_pos = sample_data.loop_end.map(|e| e as f64).unwrap_or(sample_data.data.len() as f64);
|
||||||
|
|
||||||
|
if voice.pos >= end_pos {
|
||||||
|
if voice.loop_mode == LoopMode::On {
|
||||||
|
let loop_start = sample_data.loop_start.unwrap_or(0) as f64;
|
||||||
|
voice.pos = loop_start + (voice.pos - end_pos);
|
||||||
|
} else {
|
||||||
|
voice.sample = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp final para evitar clipping (opcional se usarmos f32, mas bom para fidelidade)
|
||||||
|
for sample in buffer.iter_mut() {
|
||||||
|
*sample = sample.clamp(-1.0, 1.0);
|
||||||
|
}
|
||||||
|
self.last_processing_time = start.elapsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,15 @@
|
|||||||
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
mod audio_mixer;
|
||||||
use prometeu_core::peripherals::InputSignals;
|
|
||||||
|
use audio_mixer::AudioMixer;
|
||||||
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
use prometeu_core::peripherals::{AudioCommand, InputSignals, OUTPUT_SAMPLE_RATE};
|
||||||
use prometeu_core::Machine;
|
use prometeu_core::Machine;
|
||||||
|
use ringbuf::traits::{Consumer, Producer, Split};
|
||||||
|
use ringbuf::HeapRb;
|
||||||
|
use std::sync::Arc;
|
||||||
use winit::{
|
use winit::{
|
||||||
application::ApplicationHandler,
|
application::ApplicationHandler,
|
||||||
dpi::LogicalSize,
|
dpi::LogicalSize,
|
||||||
@ -35,6 +42,12 @@ struct PrometeuApp {
|
|||||||
|
|
||||||
last_stats_update: Instant,
|
last_stats_update: Instant,
|
||||||
frames_since_last_update: u64,
|
frames_since_last_update: u64,
|
||||||
|
audio_load_accum_us: u64,
|
||||||
|
audio_load_samples: u64,
|
||||||
|
audio_perf_consumer: Option<ringbuf::wrap::CachingCons<Arc<HeapRb<u64>>>>,
|
||||||
|
|
||||||
|
audio_producer: Option<ringbuf::wrap::CachingProd<Arc<HeapRb<AudioCommand>>>>,
|
||||||
|
_audio_stream: Option<cpal::Stream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrometeuApp {
|
impl PrometeuApp {
|
||||||
@ -55,9 +68,61 @@ impl PrometeuApp {
|
|||||||
|
|
||||||
last_stats_update: Instant::now(),
|
last_stats_update: Instant::now(),
|
||||||
frames_since_last_update: 0,
|
frames_since_last_update: 0,
|
||||||
|
audio_load_accum_us: 0,
|
||||||
|
audio_load_samples: 0,
|
||||||
|
audio_perf_consumer: None,
|
||||||
|
|
||||||
|
audio_producer: None,
|
||||||
|
_audio_stream: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_audio(&mut self) {
|
||||||
|
let host = cpal::default_host();
|
||||||
|
let device = host
|
||||||
|
.default_output_device()
|
||||||
|
.expect("no output device available");
|
||||||
|
|
||||||
|
let config = cpal::StreamConfig {
|
||||||
|
channels: 2,
|
||||||
|
sample_rate: cpal::SampleRate(OUTPUT_SAMPLE_RATE),
|
||||||
|
buffer_size: cpal::BufferSize::Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
let rb = HeapRb::<AudioCommand>::new(1024);
|
||||||
|
let (prod, mut cons) = rb.split();
|
||||||
|
|
||||||
|
self.audio_producer = Some(prod);
|
||||||
|
|
||||||
|
let mut mixer = AudioMixer::new();
|
||||||
|
|
||||||
|
// Para passar dados de performance da thread de áudio para a principal
|
||||||
|
let audio_perf_rb = HeapRb::<u64>::new(64);
|
||||||
|
let (mut perf_prod, perf_cons) = audio_perf_rb.split();
|
||||||
|
|
||||||
|
let stream = device
|
||||||
|
.build_output_stream(
|
||||||
|
&config,
|
||||||
|
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
||||||
|
// Consome comandos da ringbuffer
|
||||||
|
while let Some(cmd) = cons.try_pop() {
|
||||||
|
mixer.process_command(cmd);
|
||||||
|
}
|
||||||
|
// Mixa áudio
|
||||||
|
mixer.fill_buffer(data);
|
||||||
|
// Envia tempo de processamento em microssegundos
|
||||||
|
let _ = perf_prod.try_push(mixer.last_processing_time.as_micros() as u64);
|
||||||
|
},
|
||||||
|
|err| eprintln!("audio stream error: {}", err),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("failed to build audio stream");
|
||||||
|
|
||||||
|
stream.play().expect("failed to play audio stream");
|
||||||
|
self._audio_stream = Some(stream);
|
||||||
|
self.audio_perf_consumer = Some(perf_cons);
|
||||||
|
}
|
||||||
|
|
||||||
fn window(&self) -> &'static Window {
|
fn window(&self) -> &'static Window {
|
||||||
self.window.expect("window not created yet")
|
self.window.expect("window not created yet")
|
||||||
}
|
}
|
||||||
@ -82,7 +147,7 @@ impl PrometeuApp {
|
|||||||
impl ApplicationHandler for PrometeuApp {
|
impl ApplicationHandler for PrometeuApp {
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
let attrs = WindowAttributes::default()
|
let attrs = WindowAttributes::default()
|
||||||
.with_title(format!("PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Frame: {}", 0.0, 0.0, 0))
|
.with_title(format!("PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {}% | Frame: {}", 0.0, 0.0, 0.0, 0))
|
||||||
.with_inner_size(LogicalSize::new(960.0, 540.0))
|
.with_inner_size(LogicalSize::new(960.0, 540.0))
|
||||||
.with_min_inner_size(LogicalSize::new(320.0, 180.0));
|
.with_min_inner_size(LogicalSize::new(320.0, 180.0));
|
||||||
|
|
||||||
@ -102,6 +167,8 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
|
|
||||||
self.pixels = Some(pixels);
|
self.pixels = Some(pixels);
|
||||||
|
|
||||||
|
self.init_audio();
|
||||||
|
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,10 +269,26 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
// 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz
|
// 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz
|
||||||
while self.accumulator >= self.frame_target_dt {
|
while self.accumulator >= self.frame_target_dt {
|
||||||
self.machine.step_frame(&self.input_signals);
|
self.machine.step_frame(&self.input_signals);
|
||||||
|
|
||||||
|
// Envia comandos de áudio gerados neste frame para a thread de áudio
|
||||||
|
if let Some(producer) = &mut self.audio_producer {
|
||||||
|
for cmd in self.machine.audio.commands.drain(..) {
|
||||||
|
let _ = producer.try_push(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.accumulator -= self.frame_target_dt;
|
self.accumulator -= self.frame_target_dt;
|
||||||
self.frames_since_last_update += 1;
|
self.frames_since_last_update += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drena tempos de performance do áudio
|
||||||
|
if let Some(cons) = &mut self.audio_perf_consumer {
|
||||||
|
while let Some(us) = cons.try_pop() {
|
||||||
|
self.audio_load_accum_us += us;
|
||||||
|
self.audio_load_samples += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Atualiza estatísticas a cada 1 segundo real
|
// Atualiza estatísticas a cada 1 segundo real
|
||||||
let stats_elapsed = now.duration_since(self.last_stats_update);
|
let stats_elapsed = now.duration_since(self.last_stats_update);
|
||||||
if stats_elapsed >= Duration::from_secs(1) {
|
if stats_elapsed >= Duration::from_secs(1) {
|
||||||
@ -214,17 +297,26 @@ impl ApplicationHandler for PrometeuApp {
|
|||||||
let kb = self.machine.gfx.memory_usage_bytes() as f64 / 1024.0;
|
let kb = self.machine.gfx.memory_usage_bytes() as f64 / 1024.0;
|
||||||
|
|
||||||
let frame_budget_us = 16666.0;
|
let frame_budget_us = 16666.0;
|
||||||
let cpu_load = (self.machine.last_frame_cpu_time_us as f64 / frame_budget_us) * 100.0;
|
let cpu_load_core = (self.machine.last_frame_cpu_time_us as f64 / frame_budget_us) * 100.0;
|
||||||
|
|
||||||
|
let cpu_load_audio = if self.audio_load_samples > 0 {
|
||||||
|
// O load real é (tempo total processando) / (tempo total de parede).
|
||||||
|
(self.audio_load_accum_us as f64 / stats_elapsed.as_micros() as f64) * 100.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
let title = format!(
|
let title = format!(
|
||||||
"PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% | Frame: {}",
|
"PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% (C) + {:.1}% (A) | Frame: {}",
|
||||||
kb, fps, cpu_load, self.machine.frame_index
|
kb, fps, cpu_load_core, cpu_load_audio, self.machine.frame_index
|
||||||
);
|
);
|
||||||
window.set_title(&title);
|
window.set_title(&title);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.last_stats_update = now;
|
self.last_stats_update = now;
|
||||||
self.frames_since_last_update = 0;
|
self.frames_since_last_update = 0;
|
||||||
|
self.audio_load_accum_us = 0;
|
||||||
|
self.audio_load_samples = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.request_redraw();
|
self.request_redraw();
|
||||||
|
|||||||
@ -101,9 +101,9 @@ O mundo gráfico é composto por:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Modelo Interno de uma Game Layer
|
## 5. Modelo Interno de uma Tile Layer
|
||||||
|
|
||||||
Uma Game Layer **não é um bitmap de pixels**.
|
Uma Tile Layer **não é um bitmap de pixels**.
|
||||||
Ela é composta por:
|
Ela é composta por:
|
||||||
|
|
||||||
- Um **Tilemap lógico** (índices de tiles)
|
- Um **Tilemap lógico** (índices de tiles)
|
||||||
@ -190,7 +190,7 @@ Acesso:
|
|||||||
|
|
||||||
Para cada frame:
|
Para cada frame:
|
||||||
|
|
||||||
1. Para cada Game Layer, em ordem:
|
1. Para cada Tile Layer, em ordem:
|
||||||
- Rasterizar tiles visíveis do cache
|
- Rasterizar tiles visíveis do cache
|
||||||
- Aplicar scroll, flip e transparência
|
- Aplicar scroll, flip e transparência
|
||||||
- Escrever no back buffer
|
- Escrever no back buffer
|
||||||
@ -211,10 +211,10 @@ Para cada frame:
|
|||||||
|
|
||||||
Ordem base:
|
Ordem base:
|
||||||
|
|
||||||
1. Game Layer 0
|
1. Tile Layer 0
|
||||||
2. Game Layer 1
|
2. Tile Layer 1
|
||||||
3. Game Layer 2
|
3. Tile Layer 2
|
||||||
4. Game Layer 3
|
4. Tile Layer 3
|
||||||
5. Sprites (por prioridade entre layers)
|
5. Sprites (por prioridade entre layers)
|
||||||
6. HUD Layer
|
6. HUD Layer
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user