Compare commits
2 commits
d3fb042451
...
3534d986b8
Author | SHA1 | Date | |
---|---|---|---|
Alex Janka | 3534d986b8 | ||
Alex Janka | 605d4b2abd |
480
Cargo.lock
generated
480
Cargo.lock
generated
|
@ -532,6 +532,30 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
|
checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cairo-rs"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2650f66005301bd33cc486dec076e1293c4cecf768bc7ba9bf5d2b1be339b99c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"cairo-sys-rs",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cairo-sys-rs"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd3bb3119664efbd78b5e6c93957447944f16bdbced84c17a9f41c7829b81e64"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
|
@ -583,6 +607,16 @@ dependencies = [
|
||||||
"nom",
|
"nom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-expr"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -1344,6 +1378,16 @@ dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "field-offset"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
|
||||||
|
dependencies = [
|
||||||
|
"memoffset 0.9.0",
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -1578,6 +1622,63 @@ dependencies = [
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdk-pixbuf"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6a23f8a0b5090494fd04924662d463f8386cc678dd3915015a838c1a3679b92"
|
||||||
|
dependencies = [
|
||||||
|
"gdk-pixbuf-sys",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdk-pixbuf-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3dcbd04c1b2c4834cc008b4828bc917d062483b88d26effde6342e5622028f96"
|
||||||
|
dependencies = [
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdk4"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6771942f85a2beaa220c64739395e4401b9fab4a52aba9b503fa1e6ed4d4d806"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-rs",
|
||||||
|
"gdk-pixbuf",
|
||||||
|
"gdk4-sys",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"pango",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdk4-sys"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1eb95854fab65072023a7814434f003db571d6e45c287c0b0c540c1c78bdf6ae"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-sys-rs",
|
||||||
|
"gdk-pixbuf-sys",
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
"pkg-config",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -1651,6 +1752,37 @@ version = "0.28.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gio"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2eae10b27b6dd27e22ed0d812c6387deba295e6fc004a8b379e459b663b05a02"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-util",
|
||||||
|
"gio-sys",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"pin-project-lite",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gio-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcf8e1d9219bb294636753d307b030c1e8a032062cba74f493c431a5c8b81ce4"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gl_generator"
|
name = "gl_generator"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
|
@ -1662,6 +1794,60 @@ dependencies = [
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab9e86540b5d8402e905ad4ce7d6aa544092131ab564f3102175af176b90a053"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
"gio-sys",
|
||||||
|
"glib-macros",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib-build-tools"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "108f374fff60efd14b0d70d8916e7213aed18d7dd071ba3e9334ed2dac1dc86a"
|
||||||
|
dependencies = [
|
||||||
|
"gio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib-macros"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f5897ca27a83e4cdc7b4666850bade0a2e73e17689aabafcc9acddad9d823b8"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-crate 3.1.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glib-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "630f097773d7c7a0bb3258df4e8157b47dc98bbfa0e60ad9ab56174813feced4"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -1711,6 +1897,17 @@ dependencies = [
|
||||||
"gl_generator",
|
"gl_generator",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gobject-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c85e2b1080b9418dd0c58b498da3a5c826030343e0ef07bde6a955d28de54979"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "goblin"
|
name = "goblin"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
@ -1786,17 +1983,131 @@ dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene-rs"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99e4d388e96c5f29e2b2f67045d229ddf826d0a8d6d282f94ed3b34452222c91"
|
||||||
|
dependencies = [
|
||||||
|
"glib",
|
||||||
|
"graphene-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "236ed66cc9b18d8adf233716f75de803d0bf6fc806f60d14d948974a12e240d0"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gsk4"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e8ce8dee0fd87a11002214b1204ff18c9272fbd530408f0884a0f9b25dc31de"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-rs",
|
||||||
|
"gdk4",
|
||||||
|
"glib",
|
||||||
|
"graphene-rs",
|
||||||
|
"gsk4-sys",
|
||||||
|
"libc",
|
||||||
|
"pango",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gsk4-sys"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2660a652da5b662d43924df19ba40d73f015ed427329ef51d2b1360a4e0dc0e4"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-sys-rs",
|
||||||
|
"gdk4-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"graphene-sys",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gtk4"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d26ffa3ec6316ccaa1df62d3e7f5bae1637c0acbb43f250fabef38319f73c64"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-rs",
|
||||||
|
"field-offset",
|
||||||
|
"futures-channel",
|
||||||
|
"gdk-pixbuf",
|
||||||
|
"gdk4",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"graphene-rs",
|
||||||
|
"gsk4",
|
||||||
|
"gtk4-macros",
|
||||||
|
"gtk4-sys",
|
||||||
|
"libc",
|
||||||
|
"pango",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gtk4-macros"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8b86439e9896f6f3f47c3d8077c5c8205174078760afdabd9098a8e9e937d97"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"proc-macro-crate 3.1.0",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gtk4-sys"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2abc0a6d356d59a3806021829ce6ed3e70bba3509b41a535fedcb09fae13fbc0"
|
||||||
|
dependencies = [
|
||||||
|
"cairo-sys-rs",
|
||||||
|
"gdk-pixbuf-sys",
|
||||||
|
"gdk4-sys",
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"graphene-sys",
|
||||||
|
"gsk4-sys",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gui"
|
name = "gui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cacao",
|
"cacao",
|
||||||
"cpal",
|
"cpal",
|
||||||
|
"env_logger",
|
||||||
"frontend-common",
|
"frontend-common",
|
||||||
"gb-emu-lib",
|
"gb-emu-lib",
|
||||||
|
"glib-build-tools",
|
||||||
|
"gtk4",
|
||||||
|
"libadwaita",
|
||||||
|
"log",
|
||||||
"objc2 0.3.0-beta.3",
|
"objc2 0.3.0-beta.3",
|
||||||
"raw-window-handle 0.6.0",
|
"raw-window-handle 0.6.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
"twinc_emu_vst",
|
"twinc_emu_vst",
|
||||||
"uuid 1.7.0",
|
"uuid 1.7.0",
|
||||||
]
|
]
|
||||||
|
@ -2169,6 +2480,38 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libadwaita"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91b4990248b9e1ec5e72094a2ccaea70ec3809f88f6fd52192f2af306b87c5d9"
|
||||||
|
dependencies = [
|
||||||
|
"gdk-pixbuf",
|
||||||
|
"gdk4",
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"gtk4",
|
||||||
|
"libadwaita-sys",
|
||||||
|
"libc",
|
||||||
|
"pango",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libadwaita-sys"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23a748e4e92be1265cd9e93d569c0b5dfc7814107985aa6743d670ab281ea1a8"
|
||||||
|
dependencies = [
|
||||||
|
"gdk4-sys",
|
||||||
|
"gio-sys",
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gtk4-sys",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.152"
|
version = "0.2.152"
|
||||||
|
@ -2482,6 +2825,15 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
@ -2734,7 +3086,7 @@ dependencies = [
|
||||||
"goblin",
|
"goblin",
|
||||||
"reflink",
|
"reflink",
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml 0.7.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3058,6 +3410,30 @@ dependencies = [
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pango"
|
||||||
|
version = "0.19.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7809e8af4df8d024a066106b72ca6bc7253a484ae3867041a96103ef8a13188d"
|
||||||
|
dependencies = [
|
||||||
|
"gio",
|
||||||
|
"glib",
|
||||||
|
"libc",
|
||||||
|
"pango-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pango-sys"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f52ef6a881c19fbfe3b1484df5cad411acaaba29dbec843941c3110d19f340ea"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -3259,6 +3635,30 @@ dependencies = [
|
||||||
"toml_edit 0.21.0",
|
"toml_edit 0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.78"
|
version = "1.0.78"
|
||||||
|
@ -3538,6 +3938,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 = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.30"
|
version = "0.38.30"
|
||||||
|
@ -3626,6 +4035,12 @@ dependencies = [
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "send_wrapper"
|
name = "send_wrapper"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -3829,6 +4244,25 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-deps"
|
||||||
|
version = "6.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-expr",
|
||||||
|
"heck",
|
||||||
|
"pkg-config",
|
||||||
|
"toml 0.8.10",
|
||||||
|
"version-compare",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "target-lexicon"
|
||||||
|
version = "0.12.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -3962,6 +4396,18 @@ dependencies = [
|
||||||
"toml_edit 0.19.15",
|
"toml_edit 0.19.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit 0.22.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
@ -3981,7 +4427,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow",
|
"winnow 0.5.34",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3992,7 +4438,20 @@ checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.1.0",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow",
|
"winnow 0.5.34",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.1.0",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4127,6 +4586,12 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version-compare"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -4874,6 +5339,15 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11"
|
name = "x11"
|
||||||
version = "2.21.0"
|
version = "2.21.0"
|
||||||
|
|
|
@ -4,6 +4,8 @@ default-members = ["cli"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
log = "0.4.20"
|
||||||
|
env_logger = "0.11.1"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
raw-window-handle = "0.6"
|
raw-window-handle = "0.6"
|
||||||
gb-emu-lib = { path = "./lib", features = ["config"] }
|
gb-emu-lib = { path = "./lib", features = ["config"] }
|
||||||
|
|
|
@ -12,4 +12,4 @@ frontend-common = { workspace = true }
|
||||||
gb-emu-lib = { workspace = true }
|
gb-emu-lib = { workspace = true }
|
||||||
clap = { version = "4.4", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
ctrlc = "3.4"
|
ctrlc = "3.4"
|
||||||
log = "0.4.20"
|
log = { workspace = true }
|
||||||
|
|
|
@ -28,5 +28,5 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
image = { version = "0.24", default-features = false, features = ["png"] }
|
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||||
bytemuck = "1.14"
|
bytemuck = "1.14"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
log = "0.4.20"
|
log = { workspace = true }
|
||||||
env_logger = "0.11.1"
|
env_logger = "0.11.1"
|
||||||
|
|
|
@ -9,18 +9,34 @@ identifier = "com.alexjanka.TWINC.gui"
|
||||||
osx_file_extensions = [[["Game Boy ROM", "Viewer"], ["gb", "gbc"]]]
|
osx_file_extensions = [[["Game Boy ROM", "Viewer"], ["gb", "gbc"]]]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["macos-ui", "crossplatform-ui", "force-crossplatform-ui"]
|
||||||
force-crossplatform-ui = []
|
macos-ui = ["cacao", "objc", "uuid"]
|
||||||
|
crossplatform-ui = ["gtk", "adw", "glib-build-tools"]
|
||||||
|
force-crossplatform-ui = ["crossplatform-ui"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
adw = { version = "0.6.0", package = "libadwaita", features = [
|
||||||
|
"v1_4",
|
||||||
|
"gtk_v4_12",
|
||||||
|
], optional = true }
|
||||||
frontend-common = { workspace = true }
|
frontend-common = { workspace = true }
|
||||||
gb-emu-lib = { workspace = true }
|
gb-emu-lib = { workspace = true }
|
||||||
|
gtk = { version = "0.8.0", package = "gtk4", features = [
|
||||||
|
"v4_12",
|
||||||
|
], optional = true }
|
||||||
twinc_emu_vst = { path = "../gb-vst", default-features = false }
|
twinc_emu_vst = { path = "../gb-vst", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "macos"))'.dependencies]
|
|
||||||
cacao = { git = "https://git.alexjanka.com/alex/cacao" }
|
|
||||||
objc = { version = "=0.3.0-beta.3", package = "objc2" }
|
|
||||||
uuid = { version = "1.6", features = ["v4", "fast-rng"] }
|
|
||||||
raw-window-handle = { workspace = true }
|
raw-window-handle = { workspace = true }
|
||||||
cpal = "0.15"
|
cpal = "0.15"
|
||||||
|
log = { workspace = true }
|
||||||
|
env_logger = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos"))'.dependencies]
|
||||||
|
cacao = { git = "https://git.alexjanka.com/alex/cacao", optional = true }
|
||||||
|
objc = { version = "=0.3.0-beta.3", package = "objc2", optional = true }
|
||||||
|
uuid = { version = "1.6", features = ["v4", "fast-rng"], optional = true }
|
||||||
|
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
glib-build-tools = { version = "0.19.0", optional = true }
|
||||||
|
|
8
gui/build.rs
Normal file
8
gui/build.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {
|
||||||
|
// actions
|
||||||
|
glib_build_tools::compile_resources(
|
||||||
|
&["src/crossplatform/resources"],
|
||||||
|
"src/crossplatform/resources/resources.gresource.xml",
|
||||||
|
"crossplatform_templates.gresource",
|
||||||
|
);
|
||||||
|
}
|
19
gui/src/config.rs
Normal file
19
gui/src/config.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use gb_emu_lib::config::NamedConfig;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct GuiConfig {
|
||||||
|
pub tile_window: bool,
|
||||||
|
pub layer_window: bool,
|
||||||
|
pub games_dir: Option<PathBuf>,
|
||||||
|
pub recursive: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NamedConfig for GuiConfig {
|
||||||
|
fn name() -> String {
|
||||||
|
String::from("gui")
|
||||||
|
}
|
||||||
|
}
|
26
gui/src/crossplatform/game_list_entry/imp.rs
Normal file
26
gui/src/crossplatform/game_list_entry/imp.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use std::{cell::RefCell, path::PathBuf};
|
||||||
|
|
||||||
|
use glib::Properties;
|
||||||
|
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||||
|
|
||||||
|
#[derive(Properties, Default)]
|
||||||
|
#[properties(wrapper_type = super::GameListEntryObject)]
|
||||||
|
pub struct GameListEntryObject {
|
||||||
|
#[property(get, set)]
|
||||||
|
name: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
path: RefCell<PathBuf>,
|
||||||
|
#[property(get, set)]
|
||||||
|
title: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
mbc: RefCell<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for GameListEntryObject {
|
||||||
|
const NAME: &'static str = "MyGtkAppGameListEntryObject";
|
||||||
|
type Type = super::GameListEntryObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::derived_properties]
|
||||||
|
impl ObjectImpl for GameListEntryObject {}
|
21
gui/src/crossplatform/game_list_entry/mod.rs
Normal file
21
gui/src/crossplatform/game_list_entry/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
mod imp;
|
||||||
|
|
||||||
|
use glib::Object;
|
||||||
|
use gtk::glib;
|
||||||
|
|
||||||
|
use crate::gamelist::GameListEntry;
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct GameListEntryObject(ObjectSubclass<imp::GameListEntryObject>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameListEntryObject {
|
||||||
|
pub fn new(entry: GameListEntry) -> Self {
|
||||||
|
Object::builder()
|
||||||
|
.property("name", entry.name)
|
||||||
|
.property("path", entry.path)
|
||||||
|
.property("title", entry.header.title)
|
||||||
|
.property("mbc", entry.header.cartridge_type.to_string())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
95
gui/src/crossplatform/game_list_entry_display/imp.rs
Normal file
95
gui/src/crossplatform/game_list_entry_display/imp.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use adw::prelude::*;
|
||||||
|
use adw::subclass::prelude::*;
|
||||||
|
use glib::subclass::InitializingObject;
|
||||||
|
use gtk::{
|
||||||
|
gio, glib, ColumnView, ColumnViewColumn, CompositeTemplate, ScrolledWindow, SingleSelection,
|
||||||
|
SortListModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::crossplatform::{game_list_entry::GameListEntryObject, GameListEntryColumn};
|
||||||
|
|
||||||
|
#[derive(CompositeTemplate, Default)]
|
||||||
|
#[template(resource = "/com/alexjanka/TWINC/game_list_entry_display.ui")]
|
||||||
|
pub struct GameListWindow {
|
||||||
|
#[template_child]
|
||||||
|
pub gamelist: TemplateChild<ScrolledWindow>,
|
||||||
|
pub games: RefCell<Vec<GameListEntryObject>>,
|
||||||
|
#[template_child]
|
||||||
|
pub columnview: TemplateChild<ColumnView>,
|
||||||
|
#[template_child]
|
||||||
|
pub title_column: TemplateChild<ColumnViewColumn>,
|
||||||
|
#[template_child]
|
||||||
|
pub filename_column: TemplateChild<ColumnViewColumn>,
|
||||||
|
#[template_child]
|
||||||
|
pub mbc_column: TemplateChild<ColumnViewColumn>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for GameListWindow {
|
||||||
|
const NAME: &'static str = "TwincGameList";
|
||||||
|
type Type = super::GameListWindow;
|
||||||
|
type ParentType = gtk::ApplicationWindow;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for GameListWindow {
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
self.obj().set_game_list();
|
||||||
|
|
||||||
|
let model = gio::ListStore::new::<GameListEntryObject>();
|
||||||
|
model.extend_from_slice(&self.games.borrow());
|
||||||
|
|
||||||
|
let f1 = GameListEntryColumn::new("title");
|
||||||
|
let f2 = GameListEntryColumn::new("name");
|
||||||
|
let f3 = GameListEntryColumn::new("mbc");
|
||||||
|
|
||||||
|
self.title_column.set_factory(Some(&f1.factory));
|
||||||
|
self.title_column.set_sorter(Some(&f1.sorter));
|
||||||
|
self.filename_column.set_factory(Some(&f2.factory));
|
||||||
|
self.filename_column.set_sorter(Some(&f2.sorter));
|
||||||
|
self.mbc_column.set_factory(Some(&f3.factory));
|
||||||
|
self.mbc_column.set_sorter(Some(&f3.sorter));
|
||||||
|
|
||||||
|
self.columnview
|
||||||
|
.sort_by_column(Some(&self.filename_column), gtk::SortType::Ascending);
|
||||||
|
|
||||||
|
let sort_model = SortListModel::new(Some(model), Some(self.columnview.sorter().unwrap()));
|
||||||
|
|
||||||
|
let selection_model = SingleSelection::new(Some(sort_model));
|
||||||
|
|
||||||
|
self.columnview.set_model(Some(&selection_model));
|
||||||
|
|
||||||
|
self.columnview.connect_activate(move |val, _| {
|
||||||
|
log::info!(
|
||||||
|
"activated: {:?}",
|
||||||
|
val.model()
|
||||||
|
.unwrap()
|
||||||
|
.downcast_ref::<SingleSelection>()
|
||||||
|
.unwrap()
|
||||||
|
.selected_item()
|
||||||
|
.and_then(move |v| v.downcast::<GameListEntryObject>().ok())
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for GameListWindow {}
|
||||||
|
|
||||||
|
impl WindowImpl for GameListWindow {}
|
||||||
|
|
||||||
|
impl ApplicationWindowImpl for GameListWindow {}
|
||||||
|
|
||||||
|
impl AdwApplicationWindowImpl for GameListWindow {}
|
38
gui/src/crossplatform/game_list_entry_display/mod.rs
Normal file
38
gui/src/crossplatform/game_list_entry_display/mod.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
mod imp;
|
||||||
|
|
||||||
|
use gb_emu_lib::config::CONFIG_MANAGER;
|
||||||
|
use glib::Object;
|
||||||
|
use gtk::{
|
||||||
|
gio,
|
||||||
|
glib::{self, subclass::types::ObjectSubclassIsExt},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{config::GuiConfig, gamelist::load_games};
|
||||||
|
|
||||||
|
use super::game_list_entry::GameListEntryObject;
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct GameListWindow(ObjectSubclass<imp::GameListWindow>)
|
||||||
|
@extends gtk::ApplicationWindow, gtk::Window, gtk::Widget,
|
||||||
|
@implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||||
|
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameListWindow {
|
||||||
|
pub fn new(app: &adw::Application) -> Self {
|
||||||
|
Object::builder().property("application", app).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_game_list(&self) {
|
||||||
|
self.imp().games.replace(load_and_parse_games());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_and_parse_games() -> Vec<GameListEntryObject> {
|
||||||
|
let config: GuiConfig = CONFIG_MANAGER.load_or_create_config();
|
||||||
|
load_games(config.games_dir.unwrap(), config.recursive)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(GameListEntryObject::new)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
95
gui/src/crossplatform/mod.rs
Normal file
95
gui/src/crossplatform/mod.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use adw::{prelude::*, Application};
|
||||||
|
use gtk::{gio, glib::ExitCode, CustomSorter, Label, ListItem, SignalListItemFactory};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use self::{game_list_entry::GameListEntryObject, game_list_entry_display::GameListWindow};
|
||||||
|
|
||||||
|
mod game_list_entry;
|
||||||
|
mod game_list_entry_display;
|
||||||
|
|
||||||
|
const APP_ID: &str = "com.alexjanka.TWINC.gui";
|
||||||
|
|
||||||
|
pub fn run() -> Result<(), CrossplatformUiError> {
|
||||||
|
gio::resources_register_include!("crossplatform_templates.gresource")?;
|
||||||
|
let app = Application::builder().application_id(APP_ID).build();
|
||||||
|
|
||||||
|
app.connect_activate(build_ui);
|
||||||
|
|
||||||
|
match app.run().value() {
|
||||||
|
v if v == ExitCode::SUCCESS.value() => Ok(()),
|
||||||
|
val => Err(CrossplatformUiError::GtkError(val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_ui(app: &Application) {
|
||||||
|
let window = GameListWindow::new(app);
|
||||||
|
window.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GameListEntryColumn {
|
||||||
|
factory: SignalListItemFactory,
|
||||||
|
sorter: CustomSorter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameListEntryColumn {
|
||||||
|
fn new<T: ToString>(bind_to: T) -> Self {
|
||||||
|
let factory = SignalListItemFactory::new();
|
||||||
|
factory.connect_setup(move |_, list_item| {
|
||||||
|
let label = Label::builder()
|
||||||
|
.margin_top(2)
|
||||||
|
.margin_bottom(2)
|
||||||
|
.margin_start(4)
|
||||||
|
.margin_end(4)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.unwrap()
|
||||||
|
.set_child(Some(&label));
|
||||||
|
});
|
||||||
|
let bind_to = bind_to.to_string();
|
||||||
|
|
||||||
|
{
|
||||||
|
let bind_to = bind_to.clone();
|
||||||
|
factory.connect_bind(move |_, list_item| {
|
||||||
|
let inner_object = list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.unwrap()
|
||||||
|
.item()
|
||||||
|
.and_downcast::<GameListEntryObject>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let label = list_item
|
||||||
|
.downcast_ref::<ListItem>()
|
||||||
|
.unwrap()
|
||||||
|
.child()
|
||||||
|
.and_downcast::<Label>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
label.set_label(&inner_object.property::<String>(&bind_to));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sorter = gtk::CustomSorter::new(move |left, right| {
|
||||||
|
let left = left.downcast_ref::<GameListEntryObject>().unwrap();
|
||||||
|
let right = right.downcast_ref::<GameListEntryObject>().unwrap();
|
||||||
|
let left_val: String = left.property(&bind_to);
|
||||||
|
let right_val: String = right.property(&bind_to);
|
||||||
|
|
||||||
|
left_val
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&right_val.to_lowercase())
|
||||||
|
.into()
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { factory, sorter }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum CrossplatformUiError {
|
||||||
|
#[error("GTK error")]
|
||||||
|
GtkError(i32),
|
||||||
|
#[error("glib error")]
|
||||||
|
Glib(#[from] adw::glib::Error),
|
||||||
|
}
|
45
gui/src/crossplatform/resources/game_list_entry_display.ui
Normal file
45
gui/src/crossplatform/resources/game_list_entry_display.ui
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="TwincGameList" parent="GtkApplicationWindow">
|
||||||
|
<property name="title">My GTK App</property>
|
||||||
|
<property name="default-width">600</property>
|
||||||
|
<property name="default-height">400</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="gamelist">
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
<property name="margin-start">12</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="hscrollbar-policy">GTK_POLICY_NEVER</property>
|
||||||
|
<property name="propagate-natural-height">true</property>
|
||||||
|
<property name="propagate-natural-width">true</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkColumnView" id="columnview">
|
||||||
|
<child>
|
||||||
|
<object class="GtkColumnViewColumn" id="title_column">
|
||||||
|
<property name="title">Title</property>
|
||||||
|
<property name="fixed-width">150</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkColumnViewColumn" id="filename_column">
|
||||||
|
<property name="title">Filename</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkColumnViewColumn" id="mbc_column">
|
||||||
|
<property name="title">MBC</property>
|
||||||
|
<property name="fixed-width">160</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
6
gui/src/crossplatform/resources/resources.gresource.xml
Normal file
6
gui/src/crossplatform/resources/resources.gresource.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/com/alexjanka/TWINC/">
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks">game_list_entry_display.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
41
gui/src/gamelist/mod.rs
Normal file
41
gui/src/gamelist/mod.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use gb_emu_lib::connect::{RomHeader, RomHeaderError};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GameListEntry {
|
||||||
|
pub name: String,
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub header: RomHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_games<P: AsRef<Path>>(
|
||||||
|
game_dir: P,
|
||||||
|
recursive: bool,
|
||||||
|
) -> Result<Vec<GameListEntry>, GameListError> {
|
||||||
|
let mut games = Vec::new();
|
||||||
|
for entry in std::fs::read_dir(game_dir)?.flatten() {
|
||||||
|
if recursive && entry.file_type()?.is_dir() {
|
||||||
|
if let Ok(mut recursed) = load_games(entry.path(), true) {
|
||||||
|
games.append(&mut recursed);
|
||||||
|
}
|
||||||
|
} else if entry.file_type()?.is_file() {
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
let path = entry.path();
|
||||||
|
if name.ends_with("gb") || name.ends_with("gbc") {
|
||||||
|
let header = RomHeader::parse(&std::fs::read(path.clone())?)?;
|
||||||
|
games.push(GameListEntry { name, path, header });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(games)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum GameListError {
|
||||||
|
#[error("fs error")]
|
||||||
|
Fs(#[from] std::io::Error),
|
||||||
|
#[error("rom header")]
|
||||||
|
Header(#[from] RomHeaderError),
|
||||||
|
}
|
|
@ -8,10 +8,11 @@ use cacao::appkit::{App, AppDelegate};
|
||||||
use cacao::filesystem::FileSelectPanel;
|
use cacao::filesystem::FileSelectPanel;
|
||||||
use cacao::notification_center::Dispatcher;
|
use cacao::notification_center::Dispatcher;
|
||||||
use frontend_common::audio;
|
use frontend_common::audio;
|
||||||
use gb_emu_lib::config::{NamedConfig, CONFIG_MANAGER};
|
use gb_emu_lib::config::CONFIG_MANAGER;
|
||||||
use gb_emu_lib::connect::{EmulatorCoreTrait, EmulatorMessage};
|
use gb_emu_lib::connect::{EmulatorCoreTrait, EmulatorMessage};
|
||||||
use raw_window_handle::{AppKitDisplayHandle, DisplayHandle, RawDisplayHandle};
|
use raw_window_handle::{AppKitDisplayHandle, DisplayHandle, RawDisplayHandle};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
use crate::config::GuiConfig;
|
||||||
|
|
||||||
use self::cacao_window_manager::{CacaoWindowManager, EmuWindowMessage};
|
use self::cacao_window_manager::{CacaoWindowManager, EmuWindowMessage};
|
||||||
use self::preferences::{PreferencesMessage, PreferencesUi};
|
use self::preferences::{PreferencesMessage, PreferencesUi};
|
||||||
|
@ -35,23 +36,10 @@ pub(crate) enum CoreMessage {
|
||||||
OpenRom(PathBuf),
|
OpenRom(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct MacGuiConfig {
|
|
||||||
pub tile_window: bool,
|
|
||||||
pub layer_window: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NamedConfig for MacGuiConfig {
|
|
||||||
fn name() -> String {
|
|
||||||
String::from("mac-gui")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TwincUiApp {
|
pub(crate) struct TwincUiApp {
|
||||||
preferences: RwLock<Window<PreferencesUi>>,
|
preferences: RwLock<Window<PreferencesUi>>,
|
||||||
current_game: RwLock<CacaoWindowManager>,
|
current_game: RwLock<CacaoWindowManager>,
|
||||||
gui_config: RwLock<MacGuiConfig>,
|
gui_config: RwLock<GuiConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TwincUiApp {
|
impl TwincUiApp {
|
||||||
|
@ -209,7 +197,7 @@ impl Dispatcher for TwincUiApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn menu(config: &MacGuiConfig) -> Vec<Menu> {
|
fn menu(config: &GuiConfig) -> Vec<Menu> {
|
||||||
vec![
|
vec![
|
||||||
Menu::new(
|
Menu::new(
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -1,7 +1,28 @@
|
||||||
#[cfg(all(target_os = "macos", not(target_feature = "force-crossplatform-ui")))]
|
#[cfg(not(all(
|
||||||
|
target_os = "macos",
|
||||||
|
all(feature = "macos-ui", not(feature = "force-crossplatform-ui"))
|
||||||
|
)))]
|
||||||
|
mod crossplatform;
|
||||||
|
#[cfg(all(target_os = "macos", feature = "macos-ui",))]
|
||||||
mod macos;
|
mod macos;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod gamelist;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(all(target_os = "macos", not(target_feature = "force-crossplatform-ui")))]
|
env_logger::init();
|
||||||
cacao::appkit::App::new("com.alexjanka.cacao-test", macos::TwincUiApp::default()).run();
|
#[cfg(not(all(
|
||||||
|
target_os = "macos",
|
||||||
|
all(feature = "macos-ui", not(feature = "force-crossplatform-ui"))
|
||||||
|
)))]
|
||||||
|
{
|
||||||
|
crossplatform::run().unwrap();
|
||||||
|
}
|
||||||
|
#[cfg(all(
|
||||||
|
target_os = "macos",
|
||||||
|
all(feature = "macos-ui", not(feature = "force-crossplatform-ui"))
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
cacao::appkit::App::new("com.alexjanka.cacao-test", macos::TwincUiApp::default()).run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ ron = { version = "0.8", optional = true }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
wgpu = { version = "0.19", optional = true }
|
wgpu = { version = "0.19", optional = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
log = "0.4.20"
|
log = { workspace = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
naga = { version = "0.19", optional = true, features = ["wgsl-in", "spv-out"] }
|
naga = { version = "0.19", optional = true, features = ["wgsl-in", "spv-out"] }
|
||||||
|
|
|
@ -7,7 +7,9 @@ pub use crate::processor::memory::mmio::gpu::Colour;
|
||||||
pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState};
|
pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState};
|
||||||
pub use crate::processor::memory::mmio::serial::{SerialTarget, StdoutType};
|
pub use crate::processor::memory::mmio::serial::{SerialTarget, StdoutType};
|
||||||
use crate::processor::memory::rom::sram_save::SaveDataLocation;
|
use crate::processor::memory::rom::sram_save::SaveDataLocation;
|
||||||
pub use crate::processor::memory::rom::CgbRomType;
|
pub use crate::processor::memory::rom::{
|
||||||
|
licensee::LicenseeCode, CartridgeType, CgbRomType, RamSize, RomHeader, RomHeaderError, RomSize,
|
||||||
|
};
|
||||||
pub use crate::processor::memory::Rom;
|
pub use crate::processor::memory::Rom;
|
||||||
pub use crate::{HEIGHT, WIDTH};
|
pub use crate::{HEIGHT, WIDTH};
|
||||||
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
use self::{
|
use self::{
|
||||||
mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None},
|
licensee::LicenseeCode,
|
||||||
|
mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None, KB, ROM_BANK_SIZE},
|
||||||
sram_save::SaveDataLocation,
|
sram_save::SaveDataLocation,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::addresses::{CartRamAddress, RomAddress};
|
use super::addresses::{CartRamAddress, RomAddress};
|
||||||
|
|
||||||
|
pub(crate) mod licensee;
|
||||||
mod mbcs;
|
mod mbcs;
|
||||||
pub mod sram_save;
|
pub mod sram_save;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub enum CgbRomType {
|
pub enum CgbRomType {
|
||||||
Dmg,
|
Dmg,
|
||||||
CgbOptional,
|
CgbOptional,
|
||||||
|
@ -23,8 +26,173 @@ pub struct Rom {
|
||||||
pub rom_type: CgbRomType,
|
pub rom_type: CgbRomType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rom {
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) fn load(data: Vec<u8>, sram_location: Option<SaveDataLocation>) -> Self {
|
pub struct RomHeader {
|
||||||
|
pub title: String,
|
||||||
|
pub console_type: CgbRomType,
|
||||||
|
pub licensee_code: LicenseeCode,
|
||||||
|
pub sgb_flag: bool,
|
||||||
|
pub cartridge_type: CartridgeType,
|
||||||
|
pub rom_size: RomSize,
|
||||||
|
pub ram_size: Option<RamSize>,
|
||||||
|
pub mask_rom_version: u8,
|
||||||
|
pub header_checksum: u8,
|
||||||
|
pub cartridge_checksum: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum CartridgeType {
|
||||||
|
NoMapper,
|
||||||
|
Mbc1 { battery: bool },
|
||||||
|
Mbc2 { battery: bool },
|
||||||
|
Mmm01 { battery: bool },
|
||||||
|
Mbc3 { timer: bool, battery: bool },
|
||||||
|
Mbc5 { battery: bool, rumble: bool },
|
||||||
|
Mbc6,
|
||||||
|
Mbc7,
|
||||||
|
PocketCamera,
|
||||||
|
Tama5,
|
||||||
|
HuC3,
|
||||||
|
HuC1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CartridgeType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CartridgeType::NoMapper => write!(f, "No mapper"),
|
||||||
|
CartridgeType::Mbc1 { battery } => {
|
||||||
|
write!(f, "MBC1{}", if *battery { " (battery)" } else { "" })
|
||||||
|
}
|
||||||
|
CartridgeType::Mbc2 { battery } => {
|
||||||
|
write!(f, "MBC2{}", if *battery { " (battery)" } else { "" })
|
||||||
|
}
|
||||||
|
CartridgeType::Mmm01 { battery } => {
|
||||||
|
write!(f, "MMM01{}", if *battery { " (battery)" } else { "" })
|
||||||
|
}
|
||||||
|
CartridgeType::Mbc3 {
|
||||||
|
timer: false,
|
||||||
|
battery: false,
|
||||||
|
} => write!(f, "MBC3"),
|
||||||
|
CartridgeType::Mbc3 { timer, battery } => write!(
|
||||||
|
f,
|
||||||
|
"MBC3 ({}{}{})",
|
||||||
|
if *battery { "battery" } else { "" },
|
||||||
|
if *battery && *timer { " + " } else { "" },
|
||||||
|
if *timer { "RTC" } else { "" }
|
||||||
|
),
|
||||||
|
CartridgeType::Mbc5 {
|
||||||
|
battery: false,
|
||||||
|
rumble: false,
|
||||||
|
} => write!(f, "MBC5"),
|
||||||
|
CartridgeType::Mbc5 { battery, rumble } => write!(
|
||||||
|
f,
|
||||||
|
"MBC5 ({}{}{})",
|
||||||
|
if *battery { "battery" } else { "" },
|
||||||
|
if *battery && *rumble { " + " } else { "" },
|
||||||
|
if *rumble { "Rumble" } else { "" }
|
||||||
|
),
|
||||||
|
CartridgeType::Mbc6 => write!(f, "MBC6"),
|
||||||
|
CartridgeType::Mbc7 => write!(f, "MBC7"),
|
||||||
|
CartridgeType::PocketCamera => write!(f, "Pocket Camera"),
|
||||||
|
CartridgeType::Tama5 => write!(f, "Tama5"),
|
||||||
|
CartridgeType::HuC3 => write!(f, "HuC3"),
|
||||||
|
CartridgeType::HuC1 => write!(f, "HuC1"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum RomSize {
|
||||||
|
B2,
|
||||||
|
B4,
|
||||||
|
B8,
|
||||||
|
B16,
|
||||||
|
B32,
|
||||||
|
B64,
|
||||||
|
B128,
|
||||||
|
B256,
|
||||||
|
B512,
|
||||||
|
B72,
|
||||||
|
B80,
|
||||||
|
B96,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RomSize {
|
||||||
|
pub fn from(val: u8) -> Option<Self> {
|
||||||
|
match val {
|
||||||
|
0x00 => Some(Self::B2),
|
||||||
|
0x01 => Some(Self::B4),
|
||||||
|
0x02 => Some(Self::B8),
|
||||||
|
0x03 => Some(Self::B16),
|
||||||
|
0x04 => Some(Self::B32),
|
||||||
|
0x05 => Some(Self::B64),
|
||||||
|
0x06 => Some(Self::B128),
|
||||||
|
0x07 => Some(Self::B256),
|
||||||
|
0x08 => Some(Self::B512),
|
||||||
|
0x52 => Some(Self::B72),
|
||||||
|
0x53 => Some(Self::B80),
|
||||||
|
0x54 => Some(Self::B96),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_bytes(&self) -> usize {
|
||||||
|
(match self {
|
||||||
|
RomSize::B2 => 2,
|
||||||
|
RomSize::B4 => 4,
|
||||||
|
RomSize::B8 => 8,
|
||||||
|
RomSize::B16 => 16,
|
||||||
|
RomSize::B32 => 32,
|
||||||
|
RomSize::B64 => 64,
|
||||||
|
RomSize::B128 => 128,
|
||||||
|
RomSize::B256 => 256,
|
||||||
|
RomSize::B512 => 512,
|
||||||
|
RomSize::B72 => 72,
|
||||||
|
RomSize::B80 => 80,
|
||||||
|
RomSize::B96 => 96,
|
||||||
|
}) * ROM_BANK_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum RamSize {
|
||||||
|
B2,
|
||||||
|
B8,
|
||||||
|
B32,
|
||||||
|
B64,
|
||||||
|
B128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RamSize {
|
||||||
|
pub fn from(val: u8) -> Result<Option<Self>, RomHeaderError> {
|
||||||
|
match val {
|
||||||
|
0x00 => Ok(None),
|
||||||
|
0x01 => Ok(Some(Self::B2)),
|
||||||
|
0x02 => Ok(Some(Self::B8)),
|
||||||
|
0x03 => Ok(Some(Self::B32)),
|
||||||
|
0x04 => Ok(Some(Self::B128)),
|
||||||
|
0x05 => Ok(Some(Self::B64)),
|
||||||
|
_ => Err(RomHeaderError::InvalidRamSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_bytes(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
RamSize::B2 => 2 * KB,
|
||||||
|
RamSize::B8 => 8 * KB,
|
||||||
|
RamSize::B32 => 32 * KB,
|
||||||
|
RamSize::B64 => 64 * KB,
|
||||||
|
RamSize::B128 => 128 * KB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RomHeader {
|
||||||
|
pub fn parse(data: &[u8]) -> Result<Self, RomHeaderError> {
|
||||||
|
if data.len() < 0x150 {
|
||||||
|
return Err(RomHeaderError::SliceLength);
|
||||||
|
}
|
||||||
|
|
||||||
let mut title_length = 0x143;
|
let mut title_length = 0x143;
|
||||||
for (i, val) in data.iter().enumerate().take(0x143).skip(0x134) {
|
for (i, val) in data.iter().enumerate().take(0x143).skip(0x134) {
|
||||||
title_length = i;
|
title_length = i;
|
||||||
|
@ -32,38 +200,184 @@ impl Rom {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let title = from_utf8(&data[0x134..title_length])
|
let title = from_utf8(&data[0x134..title_length])?.to_string();
|
||||||
.expect("Error parsing title")
|
|
||||||
.to_string();
|
let console_type = match data[0x143] {
|
||||||
|
0x80 => CgbRomType::CgbOptional,
|
||||||
|
0xC0 => CgbRomType::CgbOnly,
|
||||||
|
_ => CgbRomType::Dmg,
|
||||||
|
};
|
||||||
|
|
||||||
|
let licensee_code = LicenseeCode::from_header(data[0x14B], [data[0x144], data[0x145]]);
|
||||||
|
|
||||||
|
let sgb_flag = data[0x146] == 0x03;
|
||||||
|
let rom_size = RomSize::from(data[0x148]).ok_or(RomHeaderError::InvalidRomSize)?;
|
||||||
|
let mut ram_size = RamSize::from(data[0x149])?;
|
||||||
|
|
||||||
|
let cartridge_type = match data[0x147] {
|
||||||
|
0x00 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::NoMapper
|
||||||
|
}
|
||||||
|
0x01 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc1 { battery: false }
|
||||||
|
}
|
||||||
|
0x02 => CartridgeType::Mbc1 { battery: false },
|
||||||
|
0x03 => CartridgeType::Mbc1 { battery: true },
|
||||||
|
0x05 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc2 { battery: false }
|
||||||
|
}
|
||||||
|
0x06 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc2 { battery: true }
|
||||||
|
}
|
||||||
|
0x0B => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mmm01 { battery: false }
|
||||||
|
}
|
||||||
|
0x0C => CartridgeType::Mmm01 { battery: false },
|
||||||
|
0x0D => CartridgeType::Mmm01 { battery: true },
|
||||||
|
0x0F => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc3 {
|
||||||
|
timer: true,
|
||||||
|
battery: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x10 => CartridgeType::Mbc3 {
|
||||||
|
timer: true,
|
||||||
|
battery: true,
|
||||||
|
},
|
||||||
|
0x11 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc3 {
|
||||||
|
timer: false,
|
||||||
|
battery: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x12 => CartridgeType::Mbc3 {
|
||||||
|
timer: false,
|
||||||
|
battery: false,
|
||||||
|
},
|
||||||
|
0x13 => CartridgeType::Mbc3 {
|
||||||
|
timer: false,
|
||||||
|
battery: true,
|
||||||
|
},
|
||||||
|
0x19 => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc5 {
|
||||||
|
battery: false,
|
||||||
|
rumble: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x1A => CartridgeType::Mbc5 {
|
||||||
|
battery: false,
|
||||||
|
rumble: false,
|
||||||
|
},
|
||||||
|
0x1B => CartridgeType::Mbc5 {
|
||||||
|
battery: true,
|
||||||
|
rumble: false,
|
||||||
|
},
|
||||||
|
0x1C => {
|
||||||
|
ram_size = None;
|
||||||
|
CartridgeType::Mbc5 {
|
||||||
|
battery: false,
|
||||||
|
rumble: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x1D => CartridgeType::Mbc5 {
|
||||||
|
battery: false,
|
||||||
|
rumble: true,
|
||||||
|
},
|
||||||
|
0x1E => CartridgeType::Mbc5 {
|
||||||
|
battery: true,
|
||||||
|
rumble: true,
|
||||||
|
},
|
||||||
|
0x20 => CartridgeType::Mbc6,
|
||||||
|
0x22 => CartridgeType::Mbc7,
|
||||||
|
0xFC => CartridgeType::PocketCamera,
|
||||||
|
0xFD => CartridgeType::Tama5,
|
||||||
|
0xFE => CartridgeType::HuC3,
|
||||||
|
0xFF => CartridgeType::HuC1,
|
||||||
|
_ => return Err(RomHeaderError::InvalidMBC),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mask_rom_version = data[0x14C];
|
||||||
|
let header_checksum = data[0x14D];
|
||||||
|
let cartridge_checksum = u16::from_be_bytes([data[0x14E], data[0x14F]]);
|
||||||
|
|
||||||
|
Ok(RomHeader {
|
||||||
|
title,
|
||||||
|
console_type,
|
||||||
|
licensee_code,
|
||||||
|
sgb_flag,
|
||||||
|
cartridge_type,
|
||||||
|
rom_size,
|
||||||
|
ram_size,
|
||||||
|
mask_rom_version,
|
||||||
|
header_checksum,
|
||||||
|
cartridge_checksum,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum RomHeaderError {
|
||||||
|
#[error("slice not long enough for rom file")]
|
||||||
|
SliceLength,
|
||||||
|
#[error("parsing UTF-8")]
|
||||||
|
Utf8(#[from] std::str::Utf8Error),
|
||||||
|
#[error("invalid ROM size")]
|
||||||
|
InvalidRomSize,
|
||||||
|
#[error("invalid RAM size")]
|
||||||
|
InvalidRamSize,
|
||||||
|
#[error("invalid MBC")]
|
||||||
|
InvalidMBC,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rom {
|
||||||
|
pub(crate) fn load(data: Vec<u8>, sram_location: Option<SaveDataLocation>) -> Self {
|
||||||
|
let header_data = RomHeader::parse(&data).unwrap();
|
||||||
|
|
||||||
let rom_type = get_cgb_rom_type(data[0x143]);
|
let rom_type = get_cgb_rom_type(data[0x143]);
|
||||||
|
|
||||||
let _sgb_flag = data[0x146];
|
let mbc: Box<dyn Mbc> = match header_data.cartridge_type {
|
||||||
let rom_size = data[0x148];
|
CartridgeType::NoMapper => Box::new(None::init(data)),
|
||||||
let ram_size = data[0x149];
|
CartridgeType::Mbc1 { battery } => Box::new(Mbc1::init(
|
||||||
let mbc: Box<dyn Mbc> = match data[0x147] {
|
data,
|
||||||
0x00 => Box::new(None::init(data)),
|
header_data.rom_size,
|
||||||
0x01 => Box::new(Mbc1::init(data, rom_size, 0, None)),
|
header_data.ram_size,
|
||||||
0x02 => Box::new(Mbc1::init(data, rom_size, ram_size, None)),
|
if battery { sram_location } else { None },
|
||||||
0x03 => Box::new(Mbc1::init(data, rom_size, ram_size, sram_location)),
|
)),
|
||||||
0x05 => Box::new(Mbc2::init(data, rom_size, None)),
|
CartridgeType::Mbc2 { battery } => Box::new(Mbc2::init(
|
||||||
0x06 => Box::new(Mbc2::init(data, rom_size, sram_location)),
|
data,
|
||||||
0x0F => Box::new(Mbc3::init(data, rom_size, 0, true, sram_location)),
|
header_data.rom_size,
|
||||||
0x10 => Box::new(Mbc3::init(data, rom_size, ram_size, true, sram_location)),
|
if battery { sram_location } else { None },
|
||||||
0x11 => Box::new(Mbc3::init(data, rom_size, 0, false, None)),
|
)),
|
||||||
0x12 => Box::new(Mbc3::init(data, rom_size, ram_size, false, None)),
|
CartridgeType::Mbc3 { timer, battery } => Box::new(Mbc3::init(
|
||||||
0x13 => Box::new(Mbc3::init(data, rom_size, ram_size, false, sram_location)),
|
data,
|
||||||
0x19 => Box::new(Mbc5::init(data, rom_size, 0, false, None)),
|
header_data.rom_size,
|
||||||
0x1A => Box::new(Mbc5::init(data, rom_size, ram_size, false, None)),
|
header_data.ram_size,
|
||||||
0x1B => Box::new(Mbc5::init(data, rom_size, ram_size, false, sram_location)),
|
timer,
|
||||||
0x1C => Box::new(Mbc5::init(data, rom_size, 0, true, None)),
|
if battery { sram_location } else { None },
|
||||||
0x1D => Box::new(Mbc5::init(data, rom_size, ram_size, true, None)),
|
)),
|
||||||
0x1E => Box::new(Mbc5::init(data, rom_size, ram_size, true, sram_location)),
|
CartridgeType::Mbc5 { battery, rumble } => Box::new(Mbc5::init(
|
||||||
0xFC => todo!(),
|
data,
|
||||||
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
|
header_data.rom_size,
|
||||||
|
header_data.ram_size,
|
||||||
|
rumble,
|
||||||
|
if battery { sram_location } else { None },
|
||||||
|
)),
|
||||||
|
_ => todo!(
|
||||||
|
"mapper {:?} not implemented yet!",
|
||||||
|
header_data.cartridge_type
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
title,
|
title: header_data.title,
|
||||||
mbc,
|
mbc,
|
||||||
rom_type,
|
rom_type,
|
||||||
}
|
}
|
||||||
|
|
351
lib/src/processor/memory/rom/licensee.rs
Normal file
351
lib/src/processor/memory/rom/licensee.rs
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum LicenseeCode {
|
||||||
|
None,
|
||||||
|
Nintendo,
|
||||||
|
Capcom,
|
||||||
|
HotB,
|
||||||
|
Jaleco,
|
||||||
|
Coconuts,
|
||||||
|
EliteSystems,
|
||||||
|
ElectronicArts,
|
||||||
|
Hudsonsoft,
|
||||||
|
ItcEntertainment,
|
||||||
|
Yanoman,
|
||||||
|
Clary,
|
||||||
|
Virgin,
|
||||||
|
PcmComplete,
|
||||||
|
SanX,
|
||||||
|
KotobukiSystems,
|
||||||
|
Seta,
|
||||||
|
Infogrames,
|
||||||
|
Bandai,
|
||||||
|
Konami,
|
||||||
|
Hector,
|
||||||
|
Banpresto,
|
||||||
|
EntertainmentI,
|
||||||
|
Gremlin,
|
||||||
|
Ubisoft,
|
||||||
|
Atlus,
|
||||||
|
Malibu,
|
||||||
|
Angel,
|
||||||
|
SpectrumHoloby,
|
||||||
|
Irem,
|
||||||
|
USGold,
|
||||||
|
Absolute,
|
||||||
|
Acclaim,
|
||||||
|
Activision,
|
||||||
|
AmericanSammy,
|
||||||
|
Gametek,
|
||||||
|
ParkPlace,
|
||||||
|
Ljn,
|
||||||
|
Matchbox,
|
||||||
|
MiltonBradley,
|
||||||
|
Mindscape,
|
||||||
|
Romstar,
|
||||||
|
NaxatSoft,
|
||||||
|
Tradewest,
|
||||||
|
Titus,
|
||||||
|
Ocean,
|
||||||
|
ElectroBrain,
|
||||||
|
Interplay,
|
||||||
|
Broderbund,
|
||||||
|
SculpturedSoft,
|
||||||
|
TheSalesCurve,
|
||||||
|
Thq,
|
||||||
|
Accolade,
|
||||||
|
TriffixEntertainment,
|
||||||
|
Microprose,
|
||||||
|
Kemco,
|
||||||
|
MisawaEntertainment,
|
||||||
|
Lozc,
|
||||||
|
TokumaShotenIntermedia,
|
||||||
|
BulletProofSoftware,
|
||||||
|
VicTokai,
|
||||||
|
Ape,
|
||||||
|
IMax,
|
||||||
|
ChunSoft,
|
||||||
|
VideoSystem,
|
||||||
|
Tsuburava,
|
||||||
|
Varie,
|
||||||
|
YonezawaSpal,
|
||||||
|
Kaneko,
|
||||||
|
Arc,
|
||||||
|
NihonBussan,
|
||||||
|
Tecmo,
|
||||||
|
Imagineer,
|
||||||
|
Nova,
|
||||||
|
HoriElectric,
|
||||||
|
Kawada,
|
||||||
|
Takara,
|
||||||
|
TechnosJapan,
|
||||||
|
ToeiAnimation,
|
||||||
|
Toho,
|
||||||
|
Namco,
|
||||||
|
AsciiNexoft,
|
||||||
|
Enix,
|
||||||
|
Hal,
|
||||||
|
Snk,
|
||||||
|
PonyCanyon,
|
||||||
|
CultureBrain,
|
||||||
|
Sunsoft,
|
||||||
|
SonyImagesoft,
|
||||||
|
Sammy,
|
||||||
|
Taito,
|
||||||
|
Squaresoft,
|
||||||
|
DataEast,
|
||||||
|
TonkinHouse,
|
||||||
|
Koei,
|
||||||
|
Ufl,
|
||||||
|
Ultra,
|
||||||
|
Vap,
|
||||||
|
Use,
|
||||||
|
Meldac,
|
||||||
|
Sofel,
|
||||||
|
Quest,
|
||||||
|
SigmaEnterprises,
|
||||||
|
AskKodansha,
|
||||||
|
CopyaSystems,
|
||||||
|
Tomy,
|
||||||
|
Ncs,
|
||||||
|
Human,
|
||||||
|
Altron,
|
||||||
|
Towachiki,
|
||||||
|
Uutaka,
|
||||||
|
Epoch,
|
||||||
|
Athena,
|
||||||
|
Asmik,
|
||||||
|
Natsume,
|
||||||
|
KingRecords,
|
||||||
|
EpicSonyRecords,
|
||||||
|
Igs,
|
||||||
|
AWave,
|
||||||
|
ExtremeEntertainment,
|
||||||
|
BAi,
|
||||||
|
Kss,
|
||||||
|
Pow,
|
||||||
|
Viacom,
|
||||||
|
OceanAcclaim,
|
||||||
|
HiTechEntertainment,
|
||||||
|
Mattel,
|
||||||
|
Lucasarts,
|
||||||
|
Sci,
|
||||||
|
TsukudaOri,
|
||||||
|
PackInSoft,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LicenseeCode {
|
||||||
|
pub fn from_header(old_licensee_code: u8, new_code: [u8; 2]) -> Self {
|
||||||
|
match old_licensee_code {
|
||||||
|
0x00 => Self::None,
|
||||||
|
0x01 => Self::Nintendo,
|
||||||
|
0x08 => Self::Capcom,
|
||||||
|
0x09 => Self::HotB,
|
||||||
|
0x0A => Self::Jaleco,
|
||||||
|
0x0B => Self::Coconuts,
|
||||||
|
0x0C => Self::EliteSystems,
|
||||||
|
0x13 => Self::ElectronicArts,
|
||||||
|
0x18 => Self::Hudsonsoft,
|
||||||
|
0x19 => Self::ItcEntertainment,
|
||||||
|
0x1A => Self::Yanoman,
|
||||||
|
0x1D => Self::Clary,
|
||||||
|
0x1F => Self::Virgin,
|
||||||
|
0x24 => Self::PcmComplete,
|
||||||
|
0x25 => Self::SanX,
|
||||||
|
0x28 => Self::KotobukiSystems,
|
||||||
|
0x29 => Self::Seta,
|
||||||
|
0x30 => Self::Infogrames,
|
||||||
|
0x31 => Self::Nintendo,
|
||||||
|
0x32 => Self::Bandai,
|
||||||
|
0x33 => match &new_code {
|
||||||
|
b"00" => Self::None,
|
||||||
|
b"01" => Self::Nintendo,
|
||||||
|
b"08" => Self::Capcom,
|
||||||
|
b"13" => Self::ElectronicArts,
|
||||||
|
b"18" => Self::Hudsonsoft,
|
||||||
|
b"19" => Self::BAi,
|
||||||
|
b"20" => Self::Kss,
|
||||||
|
b"22" => Self::Pow,
|
||||||
|
b"24" => Self::PcmComplete,
|
||||||
|
b"25" => Self::SanX,
|
||||||
|
b"28" => Self::Kemco,
|
||||||
|
b"29" => Self::Seta,
|
||||||
|
b"30" => Self::Viacom,
|
||||||
|
b"31" => Self::Nintendo,
|
||||||
|
b"32" => Self::Bandai,
|
||||||
|
b"33" => Self::OceanAcclaim,
|
||||||
|
b"34" => Self::Konami,
|
||||||
|
b"35" => Self::Hector,
|
||||||
|
b"37" => Self::Taito,
|
||||||
|
b"38" => Self::Hudsonsoft,
|
||||||
|
b"39" => Self::Banpresto,
|
||||||
|
b"41" => Self::Ubisoft,
|
||||||
|
b"42" => Self::Atlus,
|
||||||
|
b"44" => Self::Malibu,
|
||||||
|
b"46" => Self::Angel,
|
||||||
|
b"47" => Self::BulletProofSoftware,
|
||||||
|
b"49" => Self::Irem,
|
||||||
|
b"50" => Self::Absolute,
|
||||||
|
b"51" => Self::Acclaim,
|
||||||
|
b"52" => Self::Activision,
|
||||||
|
b"53" => Self::AmericanSammy,
|
||||||
|
b"54" => Self::Konami,
|
||||||
|
b"55" => Self::HiTechEntertainment,
|
||||||
|
b"56" => Self::Ljn,
|
||||||
|
b"57" => Self::Matchbox,
|
||||||
|
b"58" => Self::Mattel,
|
||||||
|
b"59" => Self::MiltonBradley,
|
||||||
|
b"60" => Self::Titus,
|
||||||
|
b"61" => Self::Virgin,
|
||||||
|
b"64" => Self::Lucasarts,
|
||||||
|
b"67" => Self::Ocean,
|
||||||
|
b"69" => Self::ElectronicArts,
|
||||||
|
b"70" => Self::Infogrames,
|
||||||
|
b"71" => Self::Interplay,
|
||||||
|
b"72" => Self::Broderbund,
|
||||||
|
b"73" => Self::SculpturedSoft,
|
||||||
|
b"75" => Self::Sci,
|
||||||
|
b"78" => Self::Thq,
|
||||||
|
b"79" => Self::Accolade,
|
||||||
|
b"80" => Self::MisawaEntertainment,
|
||||||
|
b"83" => Self::Lozc,
|
||||||
|
b"86" => Self::TokumaShotenIntermedia,
|
||||||
|
b"87" => Self::TsukudaOri,
|
||||||
|
b"91" => Self::ChunSoft,
|
||||||
|
b"92" => Self::VideoSystem,
|
||||||
|
b"93" => Self::OceanAcclaim,
|
||||||
|
b"95" => Self::Varie,
|
||||||
|
b"96" => Self::YonezawaSpal,
|
||||||
|
b"97" => Self::Kaneko,
|
||||||
|
b"99" => Self::PackInSoft,
|
||||||
|
_ => Self::None,
|
||||||
|
},
|
||||||
|
0x34 => Self::Konami,
|
||||||
|
0x35 => Self::Hector,
|
||||||
|
0x38 => Self::Capcom,
|
||||||
|
0x39 => Self::Banpresto,
|
||||||
|
0x3C => Self::EntertainmentI,
|
||||||
|
0x3E => Self::Gremlin,
|
||||||
|
0x41 => Self::Ubisoft,
|
||||||
|
0x42 => Self::Atlus,
|
||||||
|
0x44 => Self::Malibu,
|
||||||
|
0x46 => Self::Angel,
|
||||||
|
0x47 => Self::SpectrumHoloby,
|
||||||
|
0x49 => Self::Irem,
|
||||||
|
0x4A => Self::Virgin,
|
||||||
|
0x4D => Self::Malibu,
|
||||||
|
0x4F => Self::USGold,
|
||||||
|
0x50 => Self::Absolute,
|
||||||
|
0x51 => Self::Acclaim,
|
||||||
|
0x52 => Self::Activision,
|
||||||
|
0x53 => Self::AmericanSammy,
|
||||||
|
0x54 => Self::Gametek,
|
||||||
|
0x55 => Self::ParkPlace,
|
||||||
|
0x56 => Self::Ljn,
|
||||||
|
0x57 => Self::Matchbox,
|
||||||
|
0x59 => Self::MiltonBradley,
|
||||||
|
0x5A => Self::Mindscape,
|
||||||
|
0x5B => Self::Romstar,
|
||||||
|
0x5C => Self::NaxatSoft,
|
||||||
|
0x5D => Self::Tradewest,
|
||||||
|
0x60 => Self::Titus,
|
||||||
|
0x61 => Self::Virgin,
|
||||||
|
0x67 => Self::Ocean,
|
||||||
|
0x69 => Self::ElectronicArts,
|
||||||
|
0x6E => Self::EliteSystems,
|
||||||
|
0x6F => Self::ElectroBrain,
|
||||||
|
0x70 => Self::Infogrames,
|
||||||
|
0x71 => Self::Interplay,
|
||||||
|
0x72 => Self::Broderbund,
|
||||||
|
0x73 => Self::SculpturedSoft,
|
||||||
|
0x75 => Self::TheSalesCurve,
|
||||||
|
0x78 => Self::Thq,
|
||||||
|
0x79 => Self::Accolade,
|
||||||
|
0x7A => Self::TriffixEntertainment,
|
||||||
|
0x7C => Self::Microprose,
|
||||||
|
0x7F => Self::Kemco,
|
||||||
|
0x80 => Self::MisawaEntertainment,
|
||||||
|
0x83 => Self::Lozc,
|
||||||
|
0x86 => Self::TokumaShotenIntermedia,
|
||||||
|
0x8B => Self::BulletProofSoftware,
|
||||||
|
0x8C => Self::VicTokai,
|
||||||
|
0x8E => Self::Ape,
|
||||||
|
0x8F => Self::IMax,
|
||||||
|
0x91 => Self::ChunSoft,
|
||||||
|
0x92 => Self::VideoSystem,
|
||||||
|
0x93 => Self::Tsuburava,
|
||||||
|
0x95 => Self::Varie,
|
||||||
|
0x96 => Self::YonezawaSpal,
|
||||||
|
0x97 => Self::Kaneko,
|
||||||
|
0x99 => Self::Arc,
|
||||||
|
0x9A => Self::NihonBussan,
|
||||||
|
0x9B => Self::Tecmo,
|
||||||
|
0x9C => Self::Imagineer,
|
||||||
|
0x9D => Self::Banpresto,
|
||||||
|
0x9F => Self::Nova,
|
||||||
|
0xA1 => Self::HoriElectric,
|
||||||
|
0xA2 => Self::Bandai,
|
||||||
|
0xA4 => Self::Konami,
|
||||||
|
0xA6 => Self::Kawada,
|
||||||
|
0xA7 => Self::Takara,
|
||||||
|
0xA9 => Self::TechnosJapan,
|
||||||
|
0xAA => Self::Broderbund,
|
||||||
|
0xAC => Self::ToeiAnimation,
|
||||||
|
0xAD => Self::Toho,
|
||||||
|
0xAF => Self::Namco,
|
||||||
|
0xB0 => Self::Acclaim,
|
||||||
|
0xB1 => Self::AsciiNexoft,
|
||||||
|
0xB2 => Self::Bandai,
|
||||||
|
0xB4 => Self::Enix,
|
||||||
|
0xB6 => Self::Hal,
|
||||||
|
0xB7 => Self::Snk,
|
||||||
|
0xB9 => Self::PonyCanyon,
|
||||||
|
0xBA => Self::CultureBrain,
|
||||||
|
0xBB => Self::Sunsoft,
|
||||||
|
0xBD => Self::SonyImagesoft,
|
||||||
|
0xBF => Self::Sammy,
|
||||||
|
0xC0 => Self::Taito,
|
||||||
|
0xC2 => Self::Kemco,
|
||||||
|
0xC3 => Self::Squaresoft,
|
||||||
|
0xC4 => Self::TokumaShotenIntermedia,
|
||||||
|
0xC5 => Self::DataEast,
|
||||||
|
0xC6 => Self::TonkinHouse,
|
||||||
|
0xC8 => Self::Koei,
|
||||||
|
0xC9 => Self::Ufl,
|
||||||
|
0xCA => Self::Ultra,
|
||||||
|
0xCB => Self::Vap,
|
||||||
|
0xCC => Self::Use,
|
||||||
|
0xCD => Self::Meldac,
|
||||||
|
0xCE => Self::PonyCanyon,
|
||||||
|
0xCF => Self::Angel,
|
||||||
|
0xD0 => Self::Taito,
|
||||||
|
0xD1 => Self::Sofel,
|
||||||
|
0xD2 => Self::Quest,
|
||||||
|
0xD3 => Self::SigmaEnterprises,
|
||||||
|
0xD4 => Self::AskKodansha,
|
||||||
|
0xD6 => Self::NaxatSoft,
|
||||||
|
0xD7 => Self::CopyaSystems,
|
||||||
|
0xD9 => Self::Banpresto,
|
||||||
|
0xDA => Self::Tomy,
|
||||||
|
0xDB => Self::Ljn,
|
||||||
|
0xDD => Self::Ncs,
|
||||||
|
0xDE => Self::Human,
|
||||||
|
0xDF => Self::Altron,
|
||||||
|
0xE0 => Self::Jaleco,
|
||||||
|
0xE1 => Self::Towachiki,
|
||||||
|
0xE2 => Self::Uutaka,
|
||||||
|
0xE3 => Self::Varie,
|
||||||
|
0xE5 => Self::Epoch,
|
||||||
|
0xE7 => Self::Athena,
|
||||||
|
0xE8 => Self::Asmik,
|
||||||
|
0xE9 => Self::Natsume,
|
||||||
|
0xEA => Self::KingRecords,
|
||||||
|
0xEB => Self::Atlus,
|
||||||
|
0xEC => Self::EpicSonyRecords,
|
||||||
|
0xEE => Self::Igs,
|
||||||
|
0xF0 => Self::AWave,
|
||||||
|
0xF3 => Self::ExtremeEntertainment,
|
||||||
|
0xFF => Self::Ljn,
|
||||||
|
_ => Self::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,8 @@ pub use mbc5::Mbc5;
|
||||||
pub use none::None;
|
pub use none::None;
|
||||||
|
|
||||||
pub(super) const KB: usize = 1024;
|
pub(super) const KB: usize = 1024;
|
||||||
const ROM_BANK_SIZE: usize = 16 * KB;
|
pub(super) const ROM_BANK_SIZE: usize = 16 * KB;
|
||||||
const RAM_BANK_SIZE: usize = 8 * KB;
|
pub(super) const RAM_BANK_SIZE: usize = 8 * KB;
|
||||||
|
|
||||||
pub(super) trait Mbc: Send {
|
pub(super) trait Mbc: Send {
|
||||||
// addresses 0x0000 - 0x7FFF
|
// addresses 0x0000 - 0x7FFF
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||||
use crate::processor::memory::{
|
use crate::processor::memory::{
|
||||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
rom::{
|
||||||
|
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||||
|
RamSize, RomSize,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -25,13 +28,13 @@ pub struct Mbc1 {
|
||||||
impl Mbc1 {
|
impl Mbc1 {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
rom_size: u8,
|
rom_size: RomSize,
|
||||||
ram_size: u8,
|
ram_size: Option<RamSize>,
|
||||||
save_file: Option<SaveDataLocation>,
|
save_file: Option<SaveDataLocation>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
let rom_len = rom_size.size_bytes();
|
||||||
// in kb
|
// in kb
|
||||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
let ram = ram_size.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
rom_len,
|
rom_len,
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use super::{rom_banks, Mbc, ROM_BANK_SIZE};
|
use super::Mbc;
|
||||||
use crate::processor::memory::{
|
use crate::processor::memory::{
|
||||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
rom::{
|
||||||
|
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||||
|
RomSize,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Mbc2 {
|
pub struct Mbc2 {
|
||||||
|
@ -13,8 +16,8 @@ pub struct Mbc2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mbc2 {
|
impl Mbc2 {
|
||||||
pub fn init(data: Vec<u8>, rom_size: u8, save_file: Option<SaveDataLocation>) -> Self {
|
pub fn init(data: Vec<u8>, rom_size: RomSize, save_file: Option<SaveDataLocation>) -> Self {
|
||||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
let rom_len = rom_size.size_bytes();
|
||||||
let ram = MaybeBufferedSram::new(save_file, 512);
|
let ram = MaybeBufferedSram::new(save_file, 512);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::{
|
processor::memory::{
|
||||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
rom::{
|
||||||
|
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||||
|
RamSize, RomSize,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
util::set_or_clear_bit,
|
util::set_or_clear_bit,
|
||||||
};
|
};
|
||||||
|
@ -95,19 +98,21 @@ pub struct Mbc3 {
|
||||||
impl Mbc3 {
|
impl Mbc3 {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
rom_size: u8,
|
rom_size: RomSize,
|
||||||
ram_size: u8,
|
ram_size: Option<RamSize>,
|
||||||
rtc: bool,
|
rtc: bool,
|
||||||
save_file: Option<SaveDataLocation>,
|
save_file: Option<SaveDataLocation>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
let ram = ram_size
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
rom_bank: 1,
|
rom_bank: 1,
|
||||||
rom_size: rom_banks(rom_size) * ROM_BANK_SIZE,
|
rom_size: rom_size.size_bytes(),
|
||||||
ram,
|
ram,
|
||||||
ram_bank: RamBank::Ram(0),
|
ram_bank: RamBank::Ram(0),
|
||||||
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
|
ram_size: ram_size.map(|s| s.size_bytes()).unwrap_or(0),
|
||||||
ram_enabled: false,
|
ram_enabled: false,
|
||||||
rtc: if rtc { Some(Rtc::default()) } else { None },
|
rtc: if rtc { Some(Rtc::default()) } else { None },
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::{
|
processor::memory::{
|
||||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
rom::{
|
||||||
|
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||||
|
RamSize, RomSize,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
util::get_bit,
|
util::get_bit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||||
|
|
||||||
pub struct Mbc5 {
|
pub struct Mbc5 {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
@ -23,19 +26,21 @@ pub struct Mbc5 {
|
||||||
impl Mbc5 {
|
impl Mbc5 {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
rom_size: u8,
|
rom_size: RomSize,
|
||||||
ram_size: u8,
|
ram_size: Option<RamSize>,
|
||||||
rumble: bool,
|
rumble: bool,
|
||||||
save_file: Option<SaveDataLocation>,
|
save_file: Option<SaveDataLocation>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
let ram = ram_size
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
rom_bank: 1,
|
rom_bank: 1,
|
||||||
rom_size: rom_banks(rom_size) * ROM_BANK_SIZE,
|
rom_size: rom_size.size_bytes(),
|
||||||
ram,
|
ram,
|
||||||
ram_bank: 0,
|
ram_bank: 0,
|
||||||
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
|
ram_size: ram_size.map(|s| s.size_bytes()).unwrap_or(0),
|
||||||
ram_enabled: false,
|
ram_enabled: false,
|
||||||
rumble,
|
rumble,
|
||||||
is_rumbling: false,
|
is_rumbling: false,
|
||||||
|
|
Loading…
Reference in a new issue