Add WIP model parser (works for levels and Blender importer
This commit is contained in:
		
							parent
							
								
									45f38885ec
								
							
						
					
					
						commit
						8e0df74541
					
				
					 6 changed files with 2365 additions and 0 deletions
				
			
		
							
								
								
									
										802
									
								
								tools/remaster/scrap_parse/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										802
									
								
								tools/remaster/scrap_parse/Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,802 @@ | |||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "adler" | ||||
| version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "android_system_properties" | ||||
| version = "0.1.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "anyhow" | ||||
| version = "1.0.69" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "array-init" | ||||
| version = "2.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "autocfg" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "binrw" | ||||
| version = "0.11.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "272caaf6e0bfb7d508c0606e541e2c68f85c0d6352b62d0b299924eed59fe384" | ||||
| dependencies = [ | ||||
|  "array-init", | ||||
|  "binrw_derive", | ||||
|  "bytemuck", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "binrw_derive" | ||||
| version = "0.11.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fb4b28c1e534d96213c8966bb9240095757aa0909128985f97d16afd2e7257a8" | ||||
| dependencies = [ | ||||
|  "either", | ||||
|  "owo-colors", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "1.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bumpalo" | ||||
| version = "3.12.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bytemuck" | ||||
| version = "1.13.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cc" | ||||
| version = "1.0.79" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cfg-if" | ||||
| version = "1.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "chrono" | ||||
| version = "0.4.23" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" | ||||
| dependencies = [ | ||||
|  "iana-time-zone", | ||||
|  "js-sys", | ||||
|  "num-integer", | ||||
|  "num-traits", | ||||
|  "serde", | ||||
|  "time", | ||||
|  "wasm-bindgen", | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "chrono-humanize" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "32dce1ea1988dbdf9f9815ff11425828523bd2a134ec0805d2ac8af26ee6096e" | ||||
| dependencies = [ | ||||
|  "chrono", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap" | ||||
| version = "4.1.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "clap_derive", | ||||
|  "clap_lex", | ||||
|  "is-terminal", | ||||
|  "once_cell", | ||||
|  "strsim", | ||||
|  "termcolor", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_derive" | ||||
| version = "4.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" | ||||
| dependencies = [ | ||||
|  "heck", | ||||
|  "proc-macro-error", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "clap_lex" | ||||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" | ||||
| dependencies = [ | ||||
|  "os_str_bytes", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "codespan-reporting" | ||||
| version = "0.11.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" | ||||
| dependencies = [ | ||||
|  "termcolor", | ||||
|  "unicode-width", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "configparser" | ||||
| version = "3.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5458d9d1a587efaf5091602c59d299696a3877a439c8f6d461a2d3cce11df87a" | ||||
| dependencies = [ | ||||
|  "indexmap", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "core-foundation-sys" | ||||
| version = "0.8.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crc32fast" | ||||
| version = "1.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cxx" | ||||
| version = "1.0.91" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "cxxbridge-flags", | ||||
|  "cxxbridge-macro", | ||||
|  "link-cplusplus", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cxx-build" | ||||
| version = "1.0.91" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "codespan-reporting", | ||||
|  "once_cell", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "scratch", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cxxbridge-flags" | ||||
| version = "1.0.91" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cxxbridge-macro" | ||||
| version = "1.0.91" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "either" | ||||
| version = "1.8.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "errno" | ||||
| version = "0.2.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" | ||||
| dependencies = [ | ||||
|  "errno-dragonfly", | ||||
|  "libc", | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "errno-dragonfly" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "flate2" | ||||
| version = "1.0.25" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" | ||||
| dependencies = [ | ||||
|  "crc32fast", | ||||
|  "miniz_oxide", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "fs-err" | ||||
| version = "2.9.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hashbrown" | ||||
| version = "0.12.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "heck" | ||||
| version = "0.4.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hermit-abi" | ||||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "iana-time-zone" | ||||
| version = "0.1.53" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" | ||||
| dependencies = [ | ||||
|  "android_system_properties", | ||||
|  "core-foundation-sys", | ||||
|  "iana-time-zone-haiku", | ||||
|  "js-sys", | ||||
|  "wasm-bindgen", | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "iana-time-zone-haiku" | ||||
| version = "0.1.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" | ||||
| dependencies = [ | ||||
|  "cxx", | ||||
|  "cxx-build", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "indexmap" | ||||
| version = "1.9.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
|  "hashbrown", | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "io-lifetimes" | ||||
| version = "1.0.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "windows-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "is-terminal" | ||||
| version = "0.4.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" | ||||
| dependencies = [ | ||||
|  "hermit-abi", | ||||
|  "io-lifetimes", | ||||
|  "rustix", | ||||
|  "windows-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "itoa" | ||||
| version = "1.0.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "js-sys" | ||||
| version = "0.3.61" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" | ||||
| dependencies = [ | ||||
|  "wasm-bindgen", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.139" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "link-cplusplus" | ||||
| version = "1.0.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" | ||||
| dependencies = [ | ||||
|  "cc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "linux-raw-sys" | ||||
| version = "0.1.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "log" | ||||
| version = "0.4.17" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "miniz_oxide" | ||||
| version = "0.6.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" | ||||
| dependencies = [ | ||||
|  "adler", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "modular-bitfield" | ||||
| version = "0.11.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" | ||||
| dependencies = [ | ||||
|  "modular-bitfield-impl", | ||||
|  "static_assertions", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "modular-bitfield-impl" | ||||
| version = "0.11.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num-integer" | ||||
| version = "0.1.45" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
|  "num-traits", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num-traits" | ||||
| version = "0.2.15" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "once_cell" | ||||
| version = "1.17.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "os_str_bytes" | ||||
| version = "6.4.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "owo-colors" | ||||
| version = "3.5.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" | ||||
| 
 | ||||
| [[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", | ||||
|  "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]] | ||||
| name = "proc-macro2" | ||||
| version = "1.0.51" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" | ||||
| dependencies = [ | ||||
|  "unicode-ident", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "quote" | ||||
| version = "1.0.23" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rhexdump" | ||||
| version = "0.1.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c5e9af64574935e39f24d1c0313a997c8b880ca0e087c888bc6af8af31579847" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rustix" | ||||
| version = "0.36.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "errno", | ||||
|  "io-lifetimes", | ||||
|  "libc", | ||||
|  "linux-raw-sys", | ||||
|  "windows-sys", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ryu" | ||||
| version = "1.0.12" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "scrap_parse" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "anyhow", | ||||
|  "binrw", | ||||
|  "chrono", | ||||
|  "chrono-humanize", | ||||
|  "clap", | ||||
|  "configparser", | ||||
|  "flate2", | ||||
|  "fs-err", | ||||
|  "indexmap", | ||||
|  "modular-bitfield", | ||||
|  "rhexdump", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "scratch" | ||||
| version = "1.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde" | ||||
| version = "1.0.152" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" | ||||
| dependencies = [ | ||||
|  "serde_derive", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_derive" | ||||
| version = "1.0.152" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_json" | ||||
| version = "1.0.93" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" | ||||
| dependencies = [ | ||||
|  "itoa", | ||||
|  "ryu", | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "static_assertions" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strsim" | ||||
| version = "0.10.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "1.0.107" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "unicode-ident", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "termcolor" | ||||
| version = "1.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" | ||||
| dependencies = [ | ||||
|  "winapi-util", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "time" | ||||
| version = "0.1.45" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "wasi", | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "unicode-ident" | ||||
| version = "1.0.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "unicode-width" | ||||
| version = "0.1.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "version_check" | ||||
| version = "0.9.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasi" | ||||
| version = "0.10.0+wasi-snapshot-preview1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasm-bindgen" | ||||
| version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "wasm-bindgen-macro", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasm-bindgen-backend" | ||||
| version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" | ||||
| dependencies = [ | ||||
|  "bumpalo", | ||||
|  "log", | ||||
|  "once_cell", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasm-bindgen-macro" | ||||
| version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" | ||||
| dependencies = [ | ||||
|  "quote", | ||||
|  "wasm-bindgen-macro-support", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasm-bindgen-macro-support" | ||||
| version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn", | ||||
|  "wasm-bindgen-backend", | ||||
|  "wasm-bindgen-shared", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasm-bindgen-shared" | ||||
| version = "0.2.84" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi" | ||||
| version = "0.3.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" | ||||
| dependencies = [ | ||||
|  "winapi-i686-pc-windows-gnu", | ||||
|  "winapi-x86_64-pc-windows-gnu", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-i686-pc-windows-gnu" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-util" | ||||
| version = "0.1.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" | ||||
| dependencies = [ | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-x86_64-pc-windows-gnu" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-sys" | ||||
| version = "0.45.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" | ||||
| dependencies = [ | ||||
|  "windows-targets", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows-targets" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" | ||||
| dependencies = [ | ||||
|  "windows_aarch64_gnullvm", | ||||
|  "windows_aarch64_msvc", | ||||
|  "windows_i686_gnu", | ||||
|  "windows_i686_msvc", | ||||
|  "windows_x86_64_gnu", | ||||
|  "windows_x86_64_gnullvm", | ||||
|  "windows_x86_64_msvc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_aarch64_gnullvm" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_aarch64_msvc" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_i686_gnu" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_i686_msvc" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnu" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_gnullvm" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "windows_x86_64_msvc" | ||||
| version = "0.42.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" | ||||
							
								
								
									
										21
									
								
								tools/remaster/scrap_parse/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tools/remaster/scrap_parse/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| [package] | ||||
| name = "scrap_parse" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| anyhow = "1.0.69" | ||||
| binrw = "0.11.1" | ||||
| chrono = { version = "0.4.23", features = ["serde"] } | ||||
| chrono-humanize = "0.2.2" | ||||
| clap = { version = "4.1.6", features = ["derive"] } | ||||
| configparser = { version = "3.0.2", features = ["indexmap"] } | ||||
| flate2 = "1.0.25" | ||||
| fs-err = "2.9.0" | ||||
| indexmap = { version = "1.9.2", features = ["serde"] } | ||||
| modular-bitfield = "0.11.2" | ||||
| rhexdump = "0.1.1" | ||||
| serde = { version = "1.0.152", features = ["derive"] } | ||||
| serde_json = { version = "1.0.93", features = ["unbounded_depth"] } | ||||
							
								
								
									
										507
									
								
								tools/remaster/scrap_parse/blender_import.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										507
									
								
								tools/remaster/scrap_parse/blender_import.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,507 @@ | |||
| import bpy | ||||
| import sys | ||||
| import os | ||||
| import re | ||||
| import json | ||||
| import gzip | ||||
| import argparse | ||||
| import shutil | ||||
| from glob import glob | ||||
| from mathutils import Vector | ||||
| from pathlib import Path | ||||
| import numpy as np | ||||
| import itertools as ITT | ||||
| from pprint import pprint | ||||
| import bmesh | ||||
| from bpy.props import StringProperty, BoolProperty | ||||
| from bpy_extras.io_utils import ImportHelper | ||||
| from bpy.types import Operator | ||||
| 
 | ||||
| cmdline = None | ||||
| if "--" in sys.argv: | ||||
|     args = sys.argv[sys.argv.index("--") + 1 :] | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument("--save", action="store_true") | ||||
|     parser.add_argument("file_list", nargs="+") | ||||
|     cmdline = parser.parse_args(args) | ||||
| 
 | ||||
| 
 | ||||
| def fix_pos(xyz): | ||||
|     x, y, z = xyz | ||||
|     return x, z, y | ||||
| 
 | ||||
| 
 | ||||
| class ScrapImporter(object): | ||||
|     def __init__(self, options): | ||||
|         self.unhandled = set() | ||||
|         filepath = options.pop("filepath") | ||||
|         self.options = options | ||||
|         self.model_scale = 1000.0 | ||||
|         self.spawn_pos = {} | ||||
|         self.objects = {} | ||||
|         print("Loading", filepath) | ||||
|         with gzip.open(filepath, "r") as fh: | ||||
|             data = json.load(fh) | ||||
|         self.path = data.pop("path") | ||||
|         self.root = data.pop("root") | ||||
|         self.config = data.pop("config") | ||||
|         self.dummies = data.pop("dummies")["DUM"]["dummies"] | ||||
|         self.moredummies = data.pop("moredummies") | ||||
|         self.emi = data.pop("emi")["EMI"] | ||||
|         self.sm3 = data.pop("sm3")["SM3"] | ||||
| 
 | ||||
|     def make_empty(self, name, pos, rot=None): | ||||
|         empty = bpy.data.objects.new(name, None) | ||||
|         empty.empty_display_type = "PLAIN_AXES" | ||||
|         empty.empty_display_size = 0.1 | ||||
|         empty.location = Vector(pos).xzy / self.model_scale | ||||
|         if rot: | ||||
|             empty.rotation_euler = Vector(rot).xzy | ||||
|         empty.name = name | ||||
|         empty.show_name = True | ||||
|         bpy.context.scene.collection.objects.link(empty) | ||||
| 
 | ||||
|     def create_tracks(self): | ||||
|         points = {} | ||||
|         for dummy in self.dummies: | ||||
|             if dummy["name"].startswith("DM_Track"): | ||||
|                 try: | ||||
|                     _, name, idx = dummy["name"].split("_") | ||||
|                 except ValueError: | ||||
|                     continue | ||||
|                 pos = Vector(dummy["pos"]).xzy / self.model_scale | ||||
|                 points.setdefault(name, []).append((int(idx), pos)) | ||||
|         self.dummies=[d for d in self.dummies if not d["name"].startswith("DM_Track")] | ||||
|         for name, points in points.items(): | ||||
|             crv = bpy.data.curves.new(name, "CURVE") | ||||
|             crv.dimensions = "3D" | ||||
|             crv.path_duration = ( | ||||
|                 (bpy.context.scene.frame_end - bpy.context.scene.frame_start) + 1 | ||||
|             ) | ||||
|             crv.twist_mode = "Z_UP" | ||||
|             crv.twist_smooth = 1.0 | ||||
|             spline = crv.splines.new(type="NURBS") | ||||
|             spline.points.add(len(points) - 1) | ||||
|             spline.use_endpoint_u = True | ||||
|             spline.use_cyclic_u = True | ||||
|             spline.use_endpoint_v = True | ||||
|             spline.use_cyclic_v = True | ||||
|             points.sort() | ||||
|             for p, (_, co) in zip(spline.points, points): | ||||
|                 p.co = list(co) + [1.0] | ||||
|             obj = bpy.data.objects.new(name, crv) | ||||
|             bpy.context.scene.collection.objects.link(obj) | ||||
| 
 | ||||
|     def create_dummies(self): | ||||
|         for dummy in self.dummies: | ||||
|             self.make_empty(dummy["name"], dummy["pos"], dummy["rot"]) | ||||
|             if dummy["name"].startswith("DM_Player_Spawn"): | ||||
|                 self.spawn_pos[dummy["name"]] = dummy["pos"] | ||||
|         for name, dummy in self.moredummies.items(): | ||||
|             if not "Pos" in dummy: | ||||
|                 continue | ||||
|             pos = list(float(v) for v in dummy["Pos"]) | ||||
|             rot = [0, 0, 0] | ||||
|             if "Rot" in dummy: | ||||
|                 rot = list(float(v) for v in dummy["Rot"]) | ||||
|             self.make_empty(name, pos, rot) | ||||
| 
 | ||||
|     def add_light(self, name, node): | ||||
|         light = bpy.data.lights.new(name, "POINT") | ||||
|         light.energy = 100 | ||||
|         r = node["unk_10"][0] / 255  # *(node['unk_10'][3]/255) | ||||
|         g = node["unk_10"][1] / 255  # *(node['unk_10'][3]/255) | ||||
|         b = node["unk_10"][2] / 255  # *(node['unk_10'][3]/255) | ||||
|         light.color = (r, g, b) | ||||
|         light = bpy.data.objects.new(name, light) | ||||
|         light.location = Vector(node["pos"]).xzy / self.model_scale | ||||
|         light.rotation_euler = Vector(node["rot"]).xzy | ||||
|         bpy.context.scene.collection.objects.link(light) | ||||
| 
 | ||||
|     def create_nodes(self): | ||||
|         for node in self.sm3["scene"]["nodes"]: | ||||
|             node_name = node["name"] | ||||
|             node = node.get("content", {}) | ||||
|             if not node: | ||||
|                 continue | ||||
|             if node["type"] == "Camera": | ||||
|                 print(f"CAM:{node_name}") | ||||
|                 pprint(node) | ||||
|             elif node["type"] == "Light": | ||||
|                 print(f"LIGHT:{node_name}") | ||||
|                 # self.add_light(node_name, node) | ||||
| 
 | ||||
|     def run(self): | ||||
|         self.import_emi() | ||||
|         self.join_objects(self.options['merge_objects']) | ||||
|         if self.options['create_tracks']: | ||||
|             self.create_tracks() | ||||
|         if self.options['create_dummies']: | ||||
|             self.create_dummies() | ||||
|         if self.options['create_nodes']: | ||||
|             self.create_nodes() | ||||
|         if self.unhandled: | ||||
|             print("Unhandled textures:",self.unhandled) | ||||
| 
 | ||||
|     def join_objects(self, do_merge=False): | ||||
|         bpy.ops.object.select_all(action="DESELECT") | ||||
|         ctx = {} | ||||
|         for name, objs in self.objects.items(): | ||||
|             if len(objs) <= 1: | ||||
|                 continue | ||||
|             ctx = { | ||||
|                 "active_object": objs[0], | ||||
|                 "object": objs[0], | ||||
|                 "selected_objects": objs, | ||||
|                 "selected_editable_objects": objs, | ||||
|             } | ||||
|             with bpy.context.temp_override(**ctx): | ||||
|                 if do_merge: | ||||
|                     bpy.ops.object.join() | ||||
|                     objs[0].name=name | ||||
|                 else: | ||||
|                     coll=bpy.data.collections.new(name) | ||||
|                     bpy.context.scene.collection.children.link(coll) | ||||
|                     for n,obj in enumerate(objs): | ||||
|                         obj.name=f"{name}_{n:04}" | ||||
|                         coll.objects.link(obj) | ||||
|             bpy.ops.object.select_all(action="DESELECT") | ||||
| 
 | ||||
|     def import_emi(self): | ||||
|         mats = {0: None} | ||||
|         maps = {0: None} | ||||
|         for mat in self.emi["materials"]: | ||||
|             mats[mat[0]] = mat[1] | ||||
|         for tex_map in self.emi["maps"]: | ||||
|             maps[tex_map["key"]] = tex_map["data"] | ||||
|         for tri in self.emi["tri"]: | ||||
|             name = tri["name"] | ||||
|             if tri["data"]: | ||||
|                 tris = tri["data"]["tris"] | ||||
|                 for n, verts in enumerate( | ||||
|                     [tri["data"]["verts_1"], tri["data"]["verts_2"]], 1 | ||||
|                 ): | ||||
|                     if not (tris and verts): | ||||
|                         continue | ||||
|                     self.create_mesh( | ||||
|                         name=f"{name}_{n}", | ||||
|                         verts=verts, | ||||
|                         faces=tris, | ||||
|                         m_map=(tri["data"]["map_key"], maps[tri["data"]["map_key"]]), | ||||
|                         m_mat=(tri["data"]["mat_key"], mats[tri["data"]["mat_key"]]), | ||||
|                     ) | ||||
| 
 | ||||
|     def normalize_path(self, path): | ||||
|         return path.replace("\\", os.sep).replace("/", os.sep) | ||||
| 
 | ||||
|     def resolve_path(self, path): | ||||
|         file_extensions = [".png", ".bmp", ".dds", ".tga", ".alpha.dds"] | ||||
|         root_path = Path(self.normalize_path(self.root).lower()) | ||||
|         start_folder = Path(self.normalize_path(self.path).lower()).parent | ||||
|         try: | ||||
|             texture_path = Path(self.config["model"]["texturepath"] + "/") | ||||
|         except KeyError: | ||||
|             texture_path = None | ||||
|         path = Path(path.replace("/", os.sep).lower()) | ||||
|         if texture_path: | ||||
|             folders = ITT.chain( | ||||
|                 [start_folder], | ||||
|                 start_folder.parents, | ||||
|                 [texture_path], | ||||
|                 texture_path.parents, | ||||
|             ) | ||||
|         else: | ||||
|             folders = ITT.chain([start_folder], start_folder.parents) | ||||
|         for folder in folders: | ||||
|             for suffix in file_extensions: | ||||
|                 for dds in [".", "dds"]: | ||||
|                     resolved_path = ( | ||||
|                         root_path / folder / path.parent / dds / path.name | ||||
|                     ).with_suffix(suffix) | ||||
|                     if resolved_path.exists(): | ||||
|                         return str(resolved_path) | ||||
|         print(f"Failed to resolve {path}") | ||||
|         return None | ||||
| 
 | ||||
|     def get_input(self, node, name, dtype): | ||||
|         return list(filter(lambda i: (i.type, i.name) == (dtype, name), node.inputs)) | ||||
| 
 | ||||
| 
 | ||||
|     def build_material(self, mat_key, mat_def): | ||||
|         mat_props = dict(m.groups() for m in re.finditer(r"\(\+(\w+)(?::(\w*))?\)",mat_key)) | ||||
|         for k,v in mat_props.items(): | ||||
|             mat_props[k]=v or True | ||||
|         skip_names = ["entorno", "noise_trazado", "noise128", "pbasicometal"] | ||||
|         overrides = { | ||||
|             "zonaautoiluminada-a.dds" : { | ||||
|                 # "light" | ||||
|             }, | ||||
|             "flecha.000.dds": { | ||||
|                 "shader": "hologram" | ||||
|             }, | ||||
|             "mayor.000.dds": { | ||||
|                 "shader": "hologram" | ||||
|             }, | ||||
|         } | ||||
|         settings = { | ||||
|             "Emission Strength": 10.0, | ||||
|             "Specular": 0.0, | ||||
|             "Roughness": 0.0, | ||||
|             "Metallic": 0.0, | ||||
|         } | ||||
|         transparent_settings = { | ||||
|             "Transmission": 1.0, | ||||
|             "Transmission Roughness": 0.0, | ||||
|             "IOR": 1.0, | ||||
|         } | ||||
|         glass_settings = { | ||||
|             "Base Color": ( .8, .8, .8, 1.0), | ||||
|             "Metallic": 0.2, | ||||
|             "Roughness": 0.0, | ||||
|             "Specular": 0.2, | ||||
|         } | ||||
|         tex_slots=[ | ||||
|             "Base Color", | ||||
|             "Metallic", | ||||
|             None, # "Clearcoat" ? env map? | ||||
|             "Normal", | ||||
|             "Emission" | ||||
|         ] | ||||
| 
 | ||||
|         mat = bpy.data.materials.new(mat_key) | ||||
|         mat.use_nodes = True | ||||
|         node_tree = mat.node_tree | ||||
|         nodes = node_tree.nodes | ||||
|         imgs = {} | ||||
|         animated_textures={} | ||||
|         is_transparent = True | ||||
|         for slot,tex in zip(tex_slots,mat_def["maps"]): | ||||
|             if (slot is None)  and tex: | ||||
|                 self.unhandled.add(tex["texture"]) | ||||
|                 print(f"Don't know what to do with {tex}") | ||||
|             if not (tex and slot): | ||||
|                 continue | ||||
|             tex_file = self.resolve_path(tex["texture"]) | ||||
|             if tex_file is None: | ||||
|                 continue | ||||
|             tex_name = os.path.basename(tex_file) | ||||
|             if ".000." in tex_name: | ||||
|                 tex_files=glob(tex_file.replace(".000.",".*.")) | ||||
|                 num_frames=len(tex_files) | ||||
|                 animated_textures[slot]=num_frames | ||||
|             mat_props.update(overrides.get(tex_name,{})) | ||||
|             if any( | ||||
|                 tex_name.find(fragment) != -1 | ||||
|                 for fragment in skip_names | ||||
|             ): | ||||
|                 continue | ||||
|             else: | ||||
|                 is_transparent = False | ||||
|             imgs[slot]=bpy.data.images.load(tex_file) | ||||
|         for n in nodes: | ||||
|             nodes.remove(n) | ||||
|         out = nodes.new("ShaderNodeOutputMaterial") | ||||
|         out.name = "Output" | ||||
|         shader = nodes.new("ShaderNodeBsdfPrincipled") | ||||
|         is_transparent|=mat_props.get("shader")=="glass" | ||||
|         is_transparent|=mat_props.get("transp") in {"premult","filter"} | ||||
|         if is_transparent: | ||||
|             settings.update(transparent_settings) | ||||
|         if mat_props.get("shader")=="glass": | ||||
|             settings.update(glass_settings) | ||||
|         for name, value in settings.items(): | ||||
|             shader.inputs[name].default_value = value | ||||
|         sockets_used = set() | ||||
|         for socket,img in imgs.items(): | ||||
|             img_node = nodes.new("ShaderNodeTexImage") | ||||
|             img_node.name = img.name | ||||
|             img_node.image = img | ||||
|             if socket in animated_textures: | ||||
|                 img.source="SEQUENCE" | ||||
|                 num_frames=animated_textures[socket] | ||||
|                 fps_div = 2 # TODO: read from .emi file | ||||
|                 drv=img_node.image_user.driver_add("frame_offset") | ||||
|                 drv.driver.type="SCRIPTED" | ||||
|                 drv.driver.expression=f"((frame/{fps_div})%{num_frames})-1" | ||||
|                 img_node.image_user.frame_duration=1 | ||||
|                 img_node.image_user.use_cyclic=True | ||||
|                 img_node.image_user.use_auto_refresh=True | ||||
|             tex_mix_node = nodes.new("ShaderNodeMixRGB") | ||||
|             tex_mix_node.blend_type = "MULTIPLY" | ||||
|             tex_mix_node.inputs["Fac"].default_value = 0.0 | ||||
|             node_tree.links.new( | ||||
|                 img_node.outputs["Color"], tex_mix_node.inputs["Color1"] | ||||
|             ) | ||||
|             node_tree.links.new( | ||||
|                 img_node.outputs["Alpha"], tex_mix_node.inputs["Color2"] | ||||
|             ) | ||||
|             imgs[socket] = tex_mix_node | ||||
|             output_node = tex_mix_node.outputs["Color"] | ||||
|             print(img.name, "->", socket) | ||||
|             if socket == "Normal": | ||||
|                 normal_map = nodes.new("ShaderNodeNormalMap") | ||||
|                 node_tree.links.new(output_node, normal_map.inputs["Color"]) | ||||
|                 output_node = normal_map.outputs["Normal"] | ||||
|                 normal_map.inputs["Strength"].default_value = 0.4 | ||||
|             node_tree.links.new(output_node, shader.inputs[socket]) | ||||
|         shader_out=shader.outputs["BSDF"] | ||||
|         if mat_props.get("shader")=="hologram": | ||||
|             mix_shader = nodes.new("ShaderNodeMixShader") | ||||
|             transp_shader = nodes.new("ShaderNodeBsdfTransparent") | ||||
|             mix_in_1 = self.get_input(mix_shader,"Shader","SHADER")[0] | ||||
|             mix_in_2 = self.get_input(mix_shader,"Shader","SHADER")[1] | ||||
|             node_tree.links.new(transp_shader.outputs["BSDF"], mix_in_1) | ||||
|             node_tree.links.new(shader.outputs["BSDF"], mix_in_2) | ||||
|             node_tree.links.new(imgs["Base Color"].outputs["Color"],mix_shader.inputs["Fac"]) | ||||
|             node_tree.links.new(imgs["Base Color"].outputs["Color"],shader.inputs["Emission"]) | ||||
|             shader.inputs["Emission Strength"].default_value=50.0 | ||||
|             shader_out=mix_shader.outputs["Shader"] | ||||
|         if settings.get("Transmission",0.0)>0.0: | ||||
|             light_path = nodes.new("ShaderNodeLightPath") | ||||
|             mix_shader = nodes.new("ShaderNodeMixShader") | ||||
|             transp_shader = nodes.new("ShaderNodeBsdfTransparent") | ||||
|             mix_in_1 = self.get_input(mix_shader,"Shader","SHADER")[0] | ||||
|             mix_in_2 = self.get_input(mix_shader,"Shader","SHADER")[1] | ||||
|             node_tree.links.new(shader.outputs["BSDF"], mix_in_1) | ||||
|             node_tree.links.new(transp_shader.outputs["BSDF"], mix_in_2) | ||||
|             node_tree.links.new(light_path.outputs["Is Shadow Ray"], mix_shader.inputs["Fac"]) | ||||
|             if mat_props.get("transp")=="filter" or mat_props.get("shader")=="glass": | ||||
|                 node_tree.links.new(imgs["Base Color"].outputs["Color"],transp_shader.inputs["Color"]) | ||||
|             shader_out=mix_shader.outputs["Shader"] | ||||
|         node_tree.links.new(shader_out, out.inputs["Surface"]) | ||||
|         return mat | ||||
| 
 | ||||
|     def apply_maps(self, ob, m_mat, m_map): | ||||
|         mat_key, m_mat = m_mat | ||||
|         map_key, m_map = m_map  # TODO?: MAP | ||||
|         if mat_key == 0: | ||||
|             return | ||||
|         mat_name = m_mat.get("name", f"MAT:{mat_key:08X}") | ||||
|         map_name = f"MAP:{map_key:08X}" | ||||
|         if mat_name not in bpy.data.materials: | ||||
|             ob.active_material = self.build_material(mat_name, m_mat) | ||||
|         else: | ||||
|             ob.active_material = bpy.data.materials[mat_name] | ||||
| 
 | ||||
|     def create_mesh(self, name, verts, faces, m_mat, m_map): | ||||
|         if not verts["inner"]: | ||||
|             return | ||||
|         me = bpy.data.meshes.new(name) | ||||
|         me.use_auto_smooth = True | ||||
|         pos = np.array([Vector(v["xyz"]).xzy for v in verts["inner"]["data"]]) | ||||
|         pos /= self.model_scale | ||||
|         me.from_pydata(pos, [], faces) | ||||
|         normals = [v["normal"] for v in verts["inner"]["data"]] | ||||
|         vcols = [v["diffuse"] for v in verts["inner"]["data"]] | ||||
|         if all(normals): | ||||
|             normals = np.array(normals) | ||||
|             me.vertices.foreach_set("normal", normals.flatten()) | ||||
|         if not me.vertex_colors: | ||||
|             me.vertex_colors.new() | ||||
|         for (vcol, vert) in zip(vcols, me.vertex_colors[0].data): | ||||
|             vert.color = [vcol["r"], vcol["g"], vcol["b"], vcol["a"]] | ||||
|         uvlayers = {} | ||||
|         tex = [f"tex_{n+1}" for n in range(8)] | ||||
|         for face in me.polygons: | ||||
|             for vert_idx, loop_idx in zip(face.vertices, face.loop_indices): | ||||
|                 vert = verts["inner"]["data"][vert_idx] | ||||
|                 for tex_name in tex: | ||||
|                     if not vert[tex_name]: | ||||
|                         continue | ||||
|                     if not tex_name in uvlayers: | ||||
|                         uvlayers[tex_name] = me.uv_layers.new(name=tex_name) | ||||
|                     u, v = vert[tex_name] | ||||
|                     uvlayers[tex_name].data[loop_idx].uv = (u, 1.0 - v) | ||||
|         bm = bmesh.new() | ||||
|         bm.from_mesh(me) | ||||
|         if self.options['remove_dup_verts']: | ||||
|             bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001) | ||||
|         bm.to_mesh(me) | ||||
|         me.update(calc_edges=True) | ||||
|         bm.clear() | ||||
|         for poly in me.polygons: | ||||
|             poly.use_smooth = True | ||||
|         ob = bpy.data.objects.new(name, me) | ||||
|         self.apply_maps(ob, m_mat, m_map) | ||||
|         bpy.context.scene.collection.objects.link(ob) | ||||
|         self.objects.setdefault(name, []).append(ob) | ||||
|         return ob | ||||
| 
 | ||||
| 
 | ||||
| class Scrap_Load(Operator, ImportHelper): | ||||
| 
 | ||||
|     bl_idname = "scrap_utils.import_json" | ||||
|     bl_label = "Import JSON" | ||||
| 
 | ||||
|     filename_ext = ".json.gz" | ||||
|     filter_glob: StringProperty(default="*.json.gz", options={"HIDDEN"}) | ||||
|      | ||||
|     create_dummies: BoolProperty( | ||||
|         name="Import dummies", | ||||
|         default=True | ||||
|     ) | ||||
| 
 | ||||
|     create_nodes: BoolProperty( | ||||
|         name="Import nodes (lights, cameras, etc)", | ||||
|         default=True | ||||
|     ) | ||||
| 
 | ||||
|     create_tracks: BoolProperty( | ||||
|             name="Create track curves", | ||||
|             default=True | ||||
|     ) | ||||
| 
 | ||||
|     merge_objects: BoolProperty( | ||||
|             name="Merge objects by name", | ||||
|             default=False | ||||
|     ) | ||||
| 
 | ||||
|     remove_dup_verts: BoolProperty( | ||||
|             name="Remove overlapping vertices\nfor smoother meshes", | ||||
|             default=True | ||||
|     ) | ||||
| 
 | ||||
|     # remove_dup_verts: BoolProperty( | ||||
|     #         name="Remove overlapping vertices for smoother meshes", | ||||
|     #         default=False | ||||
|     # ) | ||||
| 
 | ||||
| 
 | ||||
|     def execute(self, context): | ||||
|         bpy.ops.preferences.addon_enable(module = "node_arrange") | ||||
|         bpy.ops.outliner.orphans_purge(do_recursive=True) | ||||
|         importer = ScrapImporter(self.as_keywords()) | ||||
|         importer.run() | ||||
|         dg = bpy.context.evaluated_depsgraph_get() | ||||
|         dg.update() | ||||
|         return {"FINISHED"} | ||||
| 
 | ||||
| 
 | ||||
| def register(): | ||||
|     bpy.utils.register_class(Scrap_Load) | ||||
| 
 | ||||
| 
 | ||||
| def unregister(): | ||||
|     bpy.utils.unregister_class(Scrap_Load) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     if cmdline is None or not cmdline.file_list: | ||||
|         register() | ||||
|         bpy.ops.scrap_utils.import_json("INVOKE_DEFAULT") | ||||
|     else: | ||||
|         for file in cmdline.file_list: | ||||
|             bpy.context.preferences.view.show_splash = False | ||||
|             objs = bpy.data.objects | ||||
|             for obj in objs.keys(): | ||||
|                 objs.remove(objs[obj], do_unlink=True) | ||||
|             cols=bpy.data.collections | ||||
|             for col in cols: | ||||
|                 cols.remove(col) | ||||
|             importer = ScrapImporter(file) | ||||
|             importer.run() | ||||
|             if cmdline.save: | ||||
|                 targetpath = Path(file).name.partition(".")[0] + ".blend" | ||||
|                 targetpath = os.path.abspath(targetpath) | ||||
|                 print("Saving", targetpath) | ||||
|                 bpy.ops.wm.save_as_mainfile(filepath=targetpath) | ||||
							
								
								
									
										103
									
								
								tools/remaster/scrap_parse/packed_loader.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								tools/remaster/scrap_parse/packed_loader.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | |||
| bl_info = { | ||||
|     "name": "Riot Archive File (RAF)", | ||||
|     "blender": (2, 71, 0), | ||||
|     "location": "File > Import", | ||||
|     "description": "Import LoL data of an Riot Archive File", | ||||
|     "category": "Import-Export"} | ||||
| 
 | ||||
| 
 | ||||
| import bpy | ||||
| from io_scene_lolraf import raf_utils | ||||
| from bpy.props import (StringProperty, BoolProperty, CollectionProperty, | ||||
|                        IntProperty) | ||||
| 
 | ||||
| 
 | ||||
| class ImportFilearchives(bpy.types.Operator): | ||||
|     """Import whole filearchives directory.""" | ||||
|     bl_idname = "import_scene.rafs" | ||||
|     bl_label = 'Import LoL filearchives' | ||||
|      | ||||
|     directory = StringProperty(name="'filearchives' folder",  | ||||
|                                subtype="DIR_PATH", options={'HIDDEN'}) | ||||
|     filter_folder = BoolProperty(default=True, options={'HIDDEN'}) | ||||
|     filter_glob = StringProperty(default="", options={'HIDDEN'}) | ||||
|      | ||||
|     def invoke(self, context, event): | ||||
|         context.window_manager.fileselect_add(self) | ||||
|         return {'RUNNING_MODAL'} | ||||
| 
 | ||||
|     def execute(self, context): | ||||
|         # TODO: Validate filepath | ||||
|         bpy.ops.ui.raf_browser('INVOKE_DEFAULT',filepath=self.directory) | ||||
|         return {'FINISHED'} | ||||
|      | ||||
| 
 | ||||
| class RAFEntry(bpy.types.PropertyGroup): | ||||
|     name = bpy.props.StringProperty() | ||||
|     selected = bpy.props.BoolProperty(name="") | ||||
| 
 | ||||
| 
 | ||||
| archive = None | ||||
| class RAFBrowser(bpy.types.Operator): | ||||
|     bl_idname = "ui.raf_browser" | ||||
|     bl_label = "RAF-browser" | ||||
|     bl_options = {'INTERNAL'} | ||||
|      | ||||
|     filepath = StringProperty() | ||||
|     current_dir = CollectionProperty(type=RAFEntry) | ||||
|     selected_index = IntProperty(default=0) | ||||
|      | ||||
|     def invoke(self, context, event): | ||||
|         global archive | ||||
|         archive = raf_utils.RAFArchive(self.filepath) | ||||
|         return context.window_manager.invoke_props_dialog(self) | ||||
|      | ||||
|     def draw(self, context): | ||||
|         if self.selected_index != -1: | ||||
|             print("new selected_index: " + str(self.selected_index)) | ||||
|             global archive | ||||
|             # TODO: change current directory of archive | ||||
|             self.current_dir.clear() | ||||
|             for dir in archive.current_dir(): | ||||
|                 entry = self.current_dir.add() | ||||
|                 entry.name = dir | ||||
|             self.selected_index = -1 | ||||
|         self.layout.template_list("RAFDirList", "", self, "current_dir", self, "selected_index") | ||||
|      | ||||
|     def execute(self, context): | ||||
|         print("execute") | ||||
|         return {'FINISHED'} | ||||
| 
 | ||||
| 
 | ||||
| class RAFDirList(bpy.types.UIList): | ||||
|     def draw_item(self, context, layout, data, item, icon, active_data, active_propname): | ||||
|         operator = data | ||||
|         raf_entry = item | ||||
|          | ||||
|         if self.layout_type in {'DEFAULT', 'COMPACT'}: | ||||
|             layout.prop(raf_entry, "name", text="", emboss=False, icon_value=icon) | ||||
|             layout.prop(raf_entry, "selected") | ||||
|         elif self.layout_type in {'GRID'}: | ||||
|             layout.alignment = 'CENTER' | ||||
|             layout.label(text="", icon_value=icon) | ||||
|          | ||||
| 
 | ||||
| def menu_func_import(self, context): | ||||
|     self.layout.operator(ImportFilearchives.bl_idname, text="LoL Filearchives") | ||||
| 
 | ||||
| 
 | ||||
| def register(): | ||||
|     bpy.utils.register_module(__name__) | ||||
|     bpy.types.INFO_MT_file_import.append(menu_func_import) | ||||
| 
 | ||||
| 
 | ||||
| def unregister(): | ||||
|     bpy.utils.unregister_module(__name__) | ||||
|     bpy.types.INFO_MT_file_import.remove(menu_func_import) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     import imp | ||||
|     imp.reload(raf_utils) | ||||
|     bpy.utils.register_module(__name__) | ||||
| 
 | ||||
							
								
								
									
										906
									
								
								tools/remaster/scrap_parse/src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										906
									
								
								tools/remaster/scrap_parse/src/main.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,906 @@ | |||
| #![allow(clippy::upper_case_acronyms, non_camel_case_types)] | ||||
| use anyhow::{anyhow, bail, Result}; | ||||
| use binrw::args; | ||||
| use binrw::prelude::*; | ||||
| use binrw::until_exclusive; | ||||
| use chrono::{DateTime, NaiveDateTime, Utc}; | ||||
| use clap::Parser; | ||||
| use configparser::ini::Ini; | ||||
| use flate2::write::GzEncoder; | ||||
| use flate2::Compression; | ||||
| use fs_err as fs; | ||||
| use indexmap::IndexMap; | ||||
| use modular_bitfield::bitfield; | ||||
| use modular_bitfield::specifiers::B2; | ||||
| use modular_bitfield::specifiers::B4; | ||||
| use modular_bitfield::BitfieldSpecifier; | ||||
| use serde::Serialize; | ||||
| use serde_json::Map; | ||||
| use serde_json::Value; | ||||
| use std::collections::HashMap; | ||||
| use std::fmt::Debug; | ||||
| use std::fs::File; | ||||
| use std::io::{BufReader, Read, Seek}; | ||||
| use std::path::Path; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Serialize, Debug)] | ||||
| #[br(import(msg: &'static str))] | ||||
| struct Unparsed<const SIZE: u64> { | ||||
|     #[br(count=SIZE, try_map=|data: Vec<u8>| Err(anyhow!("Unparsed data: {}\n{}", msg, rhexdump::hexdump(&data))))] | ||||
|     data: (), | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Serialize, Debug)] | ||||
| struct RawTable<const SIZE: u32> { | ||||
|     num_entries: u32, | ||||
|     #[br(assert(entry_size==SIZE))] | ||||
|     entry_size: u32, | ||||
|     #[br(count=num_entries, args {inner: args!{count: entry_size.try_into().unwrap()}})] | ||||
|     data: Vec<Vec<u8>>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Serialize, Debug)] | ||||
| struct Table<T: for<'a> BinRead<Args<'a> = ()> + 'static> { | ||||
|     num_entries: u32, | ||||
|     entry_size: u32, | ||||
|     #[br(count=num_entries)] | ||||
|     data: Vec<T>, | ||||
| } | ||||
| 
 | ||||
| // impl<T: for<'a> BinRead<Args<'a> = ()>> Serialize for Table<T> where T: Serialize {
 | ||||
| //     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
 | ||||
| //     where
 | ||||
| //         S: serde::Serializer {
 | ||||
| //         self.data.serialize(serializer)
 | ||||
| //     }
 | ||||
| // }
 | ||||
| 
 | ||||
| #[binread] | ||||
| struct Optional<T: for<'a> BinRead<Args<'a> = ()>> { | ||||
|     #[br(temp)] | ||||
|     has_value: u32, | ||||
|     #[br(if(has_value!=0))] | ||||
|     value: Option<T>, | ||||
| } | ||||
| 
 | ||||
| impl<T: for<'a> BinRead<Args<'a> = ()> + Debug> Debug for Optional<T> | ||||
| where | ||||
|     T: Debug, | ||||
| { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         self.value.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: for<'a> BinRead<Args<'a> = ()> + std::ops::Deref> std::ops::Deref for Optional<T> { | ||||
|     type Target = Option<T>; | ||||
| 
 | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|         &self.value | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: for<'a> BinRead<Args<'a> = ()> + Serialize> Serialize for Optional<T> { | ||||
|     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         self.value.serialize(serializer) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Serialize, Debug)] | ||||
| struct Chunk { | ||||
|     #[br(map=|c:[u8;4]| c.into_iter().map(|v| v as char).collect())] | ||||
|     magic: Vec<char>, | ||||
|     size: u32, | ||||
|     #[br(temp,count=size)] | ||||
|     data: Vec<u8>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| struct PascalString { | ||||
|     #[br(temp)] | ||||
|     length: u32, | ||||
|     #[br(count=length, map=|bytes: Vec<u8>| {
 | ||||
|         String::from_utf8_lossy(&bytes.iter().copied().take_while(|&v| v!=0).collect::<Vec<u8>>()).into_owned() | ||||
|     })] | ||||
|     string: String, | ||||
| } | ||||
| 
 | ||||
| impl Serialize for PascalString { | ||||
|     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         self.string.serialize(serializer) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Debug for PascalString { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         self.string.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct IniSection { | ||||
|     #[br(temp)] | ||||
|     num_lines: u32, | ||||
|     #[br(count=num_lines)] | ||||
|     sections: Vec<PascalString>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"INI\0")] | ||||
| #[derive(Debug)] | ||||
| struct INI { | ||||
|     size: u32, | ||||
|     #[br(temp)] | ||||
|     num_sections: u32, | ||||
|     #[br(count=num_sections)] | ||||
|     sections: Vec<IniSection>, | ||||
| } | ||||
| 
 | ||||
| impl Serialize for INI { | ||||
|     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         let blocks: Vec<String> = self | ||||
|             .sections | ||||
|             .iter() | ||||
|             .flat_map(|s| s.sections.iter()) | ||||
|             .map(|s| s.string.clone()) | ||||
|             .collect(); | ||||
|         Ini::new().read(blocks.join("\n")).serialize(serializer) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize, Clone)] | ||||
| struct RGBA { | ||||
|     r: u8, | ||||
|     g: u8, | ||||
|     b: u8, | ||||
|     a: u8, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize, Clone)] | ||||
| #[br(import(n_dims: usize))] | ||||
| struct TexCoords(#[br(count=n_dims)] Vec<f32>); | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize, Clone)] | ||||
| #[br(import(vert_fmt: FVF))] | ||||
| // https://github.com/elishacloud/dxwrapper/blob/23ffb74c4c93c4c760bb5f1de347a0b039897210/ddraw/IDirect3DDeviceX.cpp#L2642
 | ||||
| struct Vertex { | ||||
|     xyz: [f32; 3], | ||||
|     // #[br(if(vert_fmt.pos()==Pos::XYZRHW))] // seems to be unused
 | ||||
|     // rhw: Option<f32>,
 | ||||
|     #[br(if(vert_fmt.normal()))] | ||||
|     normal: Option<[f32; 3]>, | ||||
|     #[br(if(vert_fmt.point_size()))] | ||||
|     point_size: Option<[f32; 3]>, | ||||
|     #[br(if(vert_fmt.diffuse()))] | ||||
|     diffuse: Option<RGBA>, | ||||
|     #[br(if(vert_fmt.specular()))] | ||||
|     specular: Option<RGBA>, | ||||
|     #[br(if(vert_fmt.tex_count()>=1), args (vert_fmt.tex_dims(0),))] | ||||
|     tex_1: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=2), args (vert_fmt.tex_dims(1),))] | ||||
|     tex_2: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=3), args (vert_fmt.tex_dims(2),))] | ||||
|     tex_3: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=4), args (vert_fmt.tex_dims(3),))] | ||||
|     tex_4: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=5), args (vert_fmt.tex_dims(4),))] | ||||
|     tex_5: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=6), args (vert_fmt.tex_dims(5),))] | ||||
|     tex_6: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=7), args (vert_fmt.tex_dims(6),))] | ||||
|     tex_7: Option<TexCoords>, | ||||
|     #[br(if(vert_fmt.tex_count()>=8), args (vert_fmt.tex_dims(7),))] | ||||
|     tex_8: Option<TexCoords>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Serialize, PartialEq, Eq, BitfieldSpecifier)] | ||||
| #[bits = 3] | ||||
| enum Pos { | ||||
|     XYZ, | ||||
|     XYZRHW, | ||||
|     XYZB1, | ||||
|     XYZB2, | ||||
|     XYZB3, | ||||
|     XYZB4, | ||||
|     XYZB5, | ||||
| } | ||||
| 
 | ||||
| #[bitfield] | ||||
| #[repr(u32)] | ||||
| #[derive(Debug, Serialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub struct FVF { | ||||
|     reserved_1: bool, | ||||
|     pos: Pos, | ||||
|     normal: bool, | ||||
|     point_size: bool, | ||||
|     diffuse: bool, | ||||
|     specular: bool, | ||||
|     tex_count: B4, | ||||
|     tex_1: B2, | ||||
|     tex_2: B2, | ||||
|     tex_3: B2, | ||||
|     tex_4: B2, | ||||
|     tex_5: B2, | ||||
|     tex_6: B2, | ||||
|     tex_7: B2, | ||||
|     tex_8: B2, | ||||
|     rest: B4, | ||||
| } | ||||
| 
 | ||||
| impl FVF { | ||||
|     fn tex_dims(&self, tex: u8) -> usize { | ||||
|         let tex: u8 = match tex { | ||||
|             0 => self.tex_1(), | ||||
|             1 => self.tex_2(), | ||||
|             2 => self.tex_3(), | ||||
|             3 => self.tex_4(), | ||||
|             4 => self.tex_5(), | ||||
|             5 => self.tex_6(), | ||||
|             6 => self.tex_7(), | ||||
|             7 => self.tex_8(), | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
|         match tex { | ||||
|             0 => 2, | ||||
|             1 => 3, | ||||
|             2 => 4, | ||||
|             3 => 1, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn num_w(&self) -> usize { | ||||
|         use Pos::*; | ||||
|         match self.pos() { | ||||
|             XYZ | XYZRHW => 0, | ||||
|             XYZB1 => 1, | ||||
|             XYZB2 => 2, | ||||
|             XYZB3 => 3, | ||||
|             XYZB4 => 4, | ||||
|             XYZB5 => 5, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn vertex_size_from_id(fmt_id: u32) -> Result<u32> { | ||||
|     let fmt_size = match fmt_id { | ||||
|         0 => 0x0, | ||||
|         1 | 8 | 10 => 0x20, | ||||
|         2 => 0x28, | ||||
|         3 | 0xd => 0x1c, | ||||
|         4 | 7 => 0x24, | ||||
|         5 => 0x2c, | ||||
|         6 => 0x34, | ||||
|         0xb => 4, | ||||
|         0xc => 0x18, | ||||
|         0xe => 0x12, | ||||
|         0xf | 0x10 => 0x16, | ||||
|         0x11 => 0x1a, | ||||
|         other => bail!("Invalid vertex format id: {other}"), | ||||
|     }; | ||||
|     Ok(fmt_size) | ||||
| } | ||||
| 
 | ||||
| fn vertex_format_from_id(fmt_id: u32, fmt: u32) -> Result<FVF> { | ||||
|     let fvf = match fmt_id { | ||||
|         0 => 0x0, | ||||
|         1 => 0x112, | ||||
|         2 => 0x212, | ||||
|         3 => 0x1c2, | ||||
|         4 => 0x116, | ||||
|         5 => 0x252, | ||||
|         6 => 0x352, | ||||
|         7 => 0x152, | ||||
|         8 => 0x1c4, | ||||
|         10 => 0x242, | ||||
|         other => bail!("Invalid vertex format id: {other}"), | ||||
|     }; | ||||
|     if fvf != fmt { | ||||
|         bail!("Vertex format mismatch: {fvf}!={fmt}"); | ||||
|     } | ||||
|     Ok(FVF::from(fvf)) | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(import(fmt_id: u32))] | ||||
| #[derive(Debug, Serialize, Clone)] | ||||
| struct LFVFInner { | ||||
|     #[br(try_map=|v:  u32| vertex_format_from_id(fmt_id,v))] | ||||
|     vert_fmt: FVF, | ||||
|     #[br(assert(vert_size==vertex_size_from_id(fmt_id).unwrap()))] | ||||
|     vert_size: u32, | ||||
|     num_verts: u32, | ||||
|     #[br(count=num_verts, args {inner: (vert_fmt,)})] | ||||
|     data: Vec<Vertex>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"LFVF")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct LFVF { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"invalid LFVF version"))] | ||||
|     version: u32, | ||||
|     #[br(assert((0..=0x11).contains(&fmt_id),"invalid LFVF format_id"))] | ||||
|     fmt_id: u32, | ||||
|     #[br(if(fmt_id!=0),args(fmt_id))] | ||||
|     inner: Option<LFVFInner>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"MD3D")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct MD3D { | ||||
|     // TODO: mesh
 | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid MD3D version"))] | ||||
|     version: u32, | ||||
|     name: PascalString, | ||||
|     num_tris: u32, | ||||
|     #[br(assert(tri_size==6,"Invalid MD3D tri size"))] | ||||
|     tri_size: u32, | ||||
|     #[br(count=num_tris)] | ||||
|     tris: Vec<[u16; 3]>, | ||||
|     mesh_data: LFVF, | ||||
|     unk_table_1: RawTable<2>, | ||||
|     // TODO:
 | ||||
|     // ==
 | ||||
|     // unk_t1_count: u32,
 | ||||
|     // #[br(assert(unk_t1_size==2))]
 | ||||
|     // unk_t1_size: u32,
 | ||||
|     // #[br(count=unk_t1_count)]
 | ||||
|     // unk_t1_list: Vec<u16>,
 | ||||
|     // // ==
 | ||||
|     // unk_t2_count: u32,
 | ||||
|     // #[br(assert(unk_t1_size==2))]
 | ||||
|     // unk_t2_size: u32,
 | ||||
|     // #[br(count=unk_t1_count)]
 | ||||
|     // unk_t2_list: Vec<u16>,
 | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| #[serde(tag = "type")] | ||||
| enum NodeData { | ||||
|     #[br(magic = 0x0u32)] | ||||
|     Null, | ||||
|     #[br(magic = 0xa1_00_00_01_u32)] | ||||
|     TriangleMesh, // Empty?
 | ||||
|     #[br(magic = 0xa1_00_00_02_u32)] | ||||
|     Mesh(MD3D), | ||||
|     #[br(magic = 0xa2_00_00_04_u32)] | ||||
|     Camera(CAM), | ||||
|     #[br(magic = 0xa3_00_00_08_u32)] | ||||
|     Light(LUZ), | ||||
|     #[br(magic = 0xa4_00_00_10_u32)] | ||||
|     Ground(SUEL), | ||||
|     #[br(magic = 0xa5_00_00_20_u32)] | ||||
|     SisPart(Unparsed<0x10>), // TODO: Particles
 | ||||
|     #[br(magic = 0xa6_00_00_40_u32)] | ||||
|     Graphic3D(SPR3), | ||||
|     #[br(magic = 0xa6_00_00_80_u32)] | ||||
|     Flare(Unparsed<0x10>), // TODO: LensFlare?
 | ||||
|     #[br(magic = 0xa7_00_01_00u32)] | ||||
|     Portal(PORT), | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"SPR3")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct SPR3 { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid SPR3 version"))] | ||||
|     version: u32, | ||||
|     pos: [f32; 3], | ||||
|     unk_1: [u8; 8], | ||||
|     name_1: PascalString, | ||||
|     name_2: PascalString, | ||||
|     unk_2: u32, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"SUEL")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct SUEL { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid SUEL version"))] | ||||
|     version: u32, | ||||
|     bbox: [[f32; 3]; 2], | ||||
|     pos: [f32; 3], | ||||
|     unk_3: [u8; 4], | ||||
|     num_nodes: u32, | ||||
|     unk_4: [u8; 4], | ||||
|     bbox_2: [[f32; 3]; 2], | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"CAM\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct CAM { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid CAM version"))] | ||||
|     version: u32, | ||||
|     unk_1: [f32; 3], | ||||
|     origin: [f32; 3], | ||||
|     destination: [f32; 3], | ||||
|     unk_4: [u8; 4], | ||||
|     unk_5: [u8; 4], | ||||
|     unk_6: [u8; 4], | ||||
|     unk_7: [u8; 4], | ||||
|     unk_8: [u8; 4], | ||||
|     unk_9: [u8; 4], | ||||
|     unk_10: [u8; 4], | ||||
|     unk_11: [u8; 4], | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"LUZ\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct LUZ { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid LUZ version"))] | ||||
|     version: u32, | ||||
|     col: u32, | ||||
|     brightness: u32, | ||||
|     unk_3: u8, | ||||
|     pos: [f32; 3], | ||||
|     rot: [f32; 3], | ||||
|     unk_6: [u8; 8], | ||||
|     unk_7: [u8; 4], | ||||
|     unk_8: [u8; 4], | ||||
|     unk_9: [u8; 4], | ||||
|     unk_10: [u8; 4], | ||||
|     unk_11: [u8; 4], | ||||
|     unk_12: [u8; 4], | ||||
|     unk_13: u32, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"PORT")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct PORT { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid PORT version"))] | ||||
|     version: u32, | ||||
|     width: u32, | ||||
|     height: u32, | ||||
|     sides: [u32; 2], | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct Node { | ||||
|     unk_f17_0x44: u32, | ||||
|     unk_f18_0x48: u32, | ||||
|     unk_f19_0x4c: u32, | ||||
|     flags: u32, | ||||
|     unk_f20_0x50: u32, | ||||
|     name: PascalString, | ||||
|     parent: PascalString, | ||||
|     unk_f7_0x1c: [f32; 3],       // 0xc
 | ||||
|     unk_f10_0x28: [f32; 4],      // 0x10
 | ||||
|     unk_f14_0x38: f32,           // 0x4
 | ||||
|     unk_f23_0x5c: [[f32; 4]; 4], // 0x40 4x4 Matrix
 | ||||
|     unk_f39_0x9c: [[f32; 4]; 4], // 0x40 4x4 Matrix
 | ||||
|     unk_f55_0xdc: [f32; 4],      // 0x10 Vector?
 | ||||
|     unk_f59_0xec: [f32; 3],      // 0xc Vector?
 | ||||
|     node_info: Optional<INI>, | ||||
|     content: Optional<NodeData>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"MAP\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct MAP { | ||||
|     size: u32, | ||||
|     #[br(assert((2..=3).contains(&version),"invalid MAP version"))] | ||||
|     version: u32, | ||||
|     texture: PascalString, | ||||
|     unk_1: [u8; 7], | ||||
|     unk_bbox: [[f32; 2]; 2], | ||||
|     unk_2: f32, | ||||
|     #[br(if(version==3))] | ||||
|     unk_3: Option<[u8; 0xc]>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"MAT\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct MAT { | ||||
|     size: u32, | ||||
|     #[br(assert((1..=3).contains(&version),"invalid MAT version"))] | ||||
|     version: u32, | ||||
|     #[br(if(version>1))] | ||||
|     name: Option<PascalString>, | ||||
|     unk_f: [RGBA; 7], | ||||
|     unk_data: [RGBA; 0x18 / 4], | ||||
|     maps: [Optional<MAP>; 5], // Base Color, Metallic?, ???, Normal, Emission
 | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"SCN\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct SCN { | ||||
|     // 0x650220
 | ||||
|     size: u32, | ||||
|     #[br(temp,assert(version==1))] | ||||
|     version: u32, | ||||
|     model_name: PascalString, | ||||
|     node_name: PascalString, | ||||
|     node_props: Optional<INI>, | ||||
|     unk_f_1: [f32; (8 + 8) / 4], | ||||
|     unk_1: [f32; 0x18 / 4], | ||||
|     unk_f_2: f32, | ||||
|     user_props: Optional<INI>, | ||||
|     num_materials: u32, | ||||
|     #[br(count=num_materials)] | ||||
|     mat: Vec<MAT>, | ||||
|     #[br(temp,assert(unk_3==1))] | ||||
|     unk_3: u32, | ||||
|     num_nodes: u32, | ||||
|     #[br(count = num_nodes)] // 32
 | ||||
|     nodes: Vec<Node>, | ||||
|     ani: Optional<ANI>, // TODO:?
 | ||||
| } | ||||
| 
 | ||||
| fn convert_timestamp(dt: u32) -> Result<DateTime<Utc>> { | ||||
|     let Some(dt) = NaiveDateTime::from_timestamp_opt(dt.into(),0) else { | ||||
|         bail!("Invalid timestamp"); | ||||
|     }; | ||||
|     Ok(DateTime::from_utc(dt, Utc)) | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct VertexAnim { | ||||
|     n_tr: u32, | ||||
|     maybe_duration: f32, | ||||
|     #[br(count=n_tr)] | ||||
|     tris: Vec<[u8; 3]>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"EVA\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct EVA { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1,"Invalid EVA version"))] | ||||
|     version: u32, | ||||
|     num_verts: u32, | ||||
|     #[br(count=num_verts)] | ||||
|     verts: Vec<Optional<VertexAnim>>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"NAM\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct NAM { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1))] | ||||
|     version: u32, | ||||
|     primer_frames: u32, | ||||
|     frames: u32, | ||||
|     #[br(assert(flags&0xffffef60==0,"Invalid NAM flags"))] | ||||
|     flags: u32, | ||||
|     #[br(assert(opt_flags&0xfff8==0,"Invalid NAM opt_flags"))] | ||||
|     opt_flags: u32, | ||||
|     #[br(assert(stm_flags&0xfff8==0,"Invalid NAM stm_flags"))] | ||||
|     stm_flags: u32, | ||||
|     #[br(map=|_:()| flags&(opt_flags|0x8000)&stm_flags)] | ||||
|     combined_flags: u32, | ||||
|     #[br(if(combined_flags&0x1!=0))] | ||||
|     unk_flags_1: Option<u32>, | ||||
|     #[br(if(combined_flags&0x2!=0))] | ||||
|     unk_flags_2: Option<u32>, | ||||
|     #[br(if(combined_flags&0x4!=0))] | ||||
|     unk_flags_3: Option<u32>, | ||||
|     #[br(if(combined_flags&0x8!=0))] | ||||
|     unk_flags_4: Option<u32>, | ||||
|     #[br(if(combined_flags&0x10!=0))] | ||||
|     unk_flags_5: Option<u32>, | ||||
|     #[br(if(combined_flags&0x80!=0))] | ||||
|     unk_flags_6: Option<u32>, | ||||
|     #[br(if(flags&0x1000!=0))] | ||||
|     eva: Option<EVA>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"NABK")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct NABK { | ||||
|     size: u32, | ||||
|     #[br(temp,count=size)] | ||||
|     data: Vec<u8>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"ANI\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct ANI { | ||||
|     size: u32, | ||||
|     #[br(assert(version==2, "Invalid ANI version"))] | ||||
|     version: u32, | ||||
|     fps: f32, | ||||
|     unk_1: u32, | ||||
|     unk_2: u32, | ||||
|     num_objects: u32, | ||||
|     unk_flags: u32, | ||||
|     num: u32, | ||||
|     #[br(temp,count=num)] | ||||
|     data: Vec<u8>, | ||||
|     nabk: NABK, | ||||
|     #[br(count=num_objects)] | ||||
|     nam: Vec<NAM>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"SM3\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct SM3 { | ||||
|     size: u32, | ||||
|     #[br(temp,assert(const_1==0x6515f8,"Invalid timestamp"))] | ||||
|     const_1: u32, | ||||
|     #[br(try_map=convert_timestamp)] | ||||
|     time_1: DateTime<Utc>, | ||||
|     #[br(try_map=convert_timestamp)] | ||||
|     time_2: DateTime<Utc>, | ||||
|     scene: SCN, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"CM3\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct CM3 { | ||||
|     size: u32, | ||||
|     #[br(temp,assert(const_1==0x6515f8,"Invalid timestamp"))] | ||||
|     const_1: u32, | ||||
|     #[br(try_map=convert_timestamp)] | ||||
|     time_1: DateTime<Utc>, | ||||
|     #[br(try_map=convert_timestamp)] | ||||
|     time_2: DateTime<Utc>, | ||||
|     scene: SCN, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct Dummy { | ||||
|     name: PascalString, | ||||
|     pos: [f32; 3], | ||||
|     rot: [f32; 3], | ||||
|     info: Optional<INI>, | ||||
|     has_next: u32, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"DUM\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct DUM { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1, "Invalid DUM version"))] | ||||
|     version: u32, | ||||
|     num_dummies: u32, | ||||
|     unk_1: u32, | ||||
|     #[br(count=num_dummies)] | ||||
|     dummies: Vec<Dummy>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"QUAD")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct QUAD { | ||||
|     size: u32, | ||||
|     #[br(assert(version==1, "Invalid QUAD version"))] | ||||
|     version: u32, | ||||
|     mesh: u32, | ||||
|     table: Table<u16>, | ||||
|     f_4: [f32; 4], | ||||
|     num_children: u32, | ||||
|     #[br(count=num_children)] | ||||
|     children: Vec<QUAD>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"CMSH")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct CMSH { | ||||
|     size: u32, | ||||
|     #[br(assert(version==2, "Invalid CMSH version"))] | ||||
|     version: u32, | ||||
|     #[br(assert(collide_mesh_size==0x34, "Invalid collision mesh size"))] | ||||
|     collide_mesh_size: u32, | ||||
|     name: PascalString, | ||||
|     unk_1: u16, | ||||
|     sector: u16, | ||||
|     unk_2: u16, | ||||
|     index: u8, | ||||
|     unk_4: u8, | ||||
|     bbox_1: [[f32; 3]; 2], | ||||
|     #[br(temp)] | ||||
|     t_1: Table<[f32; 3]>, | ||||
|     #[br(temp)] | ||||
|     t_2: RawTable<0x1c>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"AMC\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct AMC { | ||||
|     size: u32, | ||||
|     #[br(assert(version==100,"Invalid AMC version"))] | ||||
|     version: u32, | ||||
|     #[br(assert(version_code==0, "Invalid AMC version_code"))] | ||||
|     version_code: u32, | ||||
|     bbox_1: [[f32; 3]; 2], | ||||
|     scale: f32, | ||||
|     bbox_2: [[f32; 3]; 2], | ||||
|     unk: [f32; 3], | ||||
|     cmsh: [CMSH; 2], | ||||
|     num_sectors: u32, | ||||
|     #[br(count=num_sectors)] | ||||
|     sector_col: Vec<[CMSH; 2]>, | ||||
|     unk_num_1: u32, | ||||
|     unk_num_2: u32, | ||||
|     unk_f: [f32; 4], | ||||
|     num_quads: u32, | ||||
|     #[br(count=num_quads)] | ||||
|     quads: Vec<QUAD>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(import(version: u32))] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct TriV104 { | ||||
|     #[br(if(version>=0x69))] | ||||
|     name_2: Option<PascalString>, | ||||
|     mat_key: u32, | ||||
|     map_key: u32, | ||||
|     num_tris: u32, | ||||
|     #[br(count=num_tris)] | ||||
|     tris: Vec<[u16; 3]>, | ||||
|     verts_1: LFVF, | ||||
|     verts_2: LFVF, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"TRI\0", import(version: u32))] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct TRI { | ||||
|     size: u32, | ||||
|     unk_int: u32, | ||||
|     name: PascalString, | ||||
|     unk_int_2: u32, // if 0xffffffff sometimes TriV104 has no name_2 field
 | ||||
|     #[br(args(version))] | ||||
|     data: TriV104, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct EMI_Textures { | ||||
|     key: u32, | ||||
|     #[br(if(key!=0))] | ||||
|     data: Option<(PascalString, u32, PascalString)>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[br(magic = b"EMI\0")] | ||||
| #[derive(Debug, Serialize)] | ||||
| struct EMI { | ||||
|     size: u32, | ||||
|     #[br(assert((103..=105).contains(&version)))] | ||||
|     version: u32, | ||||
|     num_materials: u32, | ||||
|     #[br(count=num_materials)] | ||||
|     materials: Vec<(u32, MAT)>, | ||||
|     #[br(parse_with = until_exclusive(|v: &EMI_Textures| v.key==0))] | ||||
|     maps: Vec<EMI_Textures>, | ||||
|     num_lists: u32, | ||||
|     #[br(count=num_lists,args{inner: (version,)})] | ||||
|     tri: Vec<TRI>, | ||||
| } | ||||
| 
 | ||||
| #[binread] | ||||
| #[derive(Debug, Serialize)] | ||||
| enum Data { | ||||
|     SM3(SM3), | ||||
|     CM3(CM3), | ||||
|     DUM(DUM), | ||||
|     AMC(AMC), | ||||
|     EMI(EMI), | ||||
| } | ||||
| 
 | ||||
| #[derive(Parser, Debug)] | ||||
| #[command(author, version, about, long_about = None)] | ||||
| struct Args { | ||||
|     root: PathBuf, | ||||
|     path: PathBuf, | ||||
| } | ||||
| 
 | ||||
| fn parse_file(path: &PathBuf) -> Result<Data> { | ||||
|     let mut rest_size = 0; | ||||
|     let mut fh = BufReader::new(fs::File::open(path)?); | ||||
|     let ret = fh.read_le()?; | ||||
|     let pos = fh | ||||
|         .stream_position() | ||||
|         .unwrap_or(0) | ||||
|         .try_into() | ||||
|         .unwrap_or(u32::MAX); | ||||
|     println!("Read {} bytes from {}", pos, path.display()); | ||||
|     let mut buffer = [0u8; 0x1000]; | ||||
|     if let Ok(n) = fh.read(&mut buffer) { | ||||
|         if n != 0 { | ||||
|             println!("Rest:\n{}", rhexdump::hexdump_offset(&buffer[..n], pos)); | ||||
|         } | ||||
|     }; | ||||
|     while let Ok(n) = fh.read(&mut buffer) { | ||||
|         if n == 0 { | ||||
|             break; | ||||
|         } | ||||
|         rest_size += n; | ||||
|     } | ||||
|     println!("+{rest_size} unparsed bytes"); | ||||
|     Ok(ret) | ||||
| } | ||||
| 
 | ||||
| fn load_ini(path: &PathBuf) -> IndexMap<String, IndexMap<String, Option<String>>> { | ||||
|     Ini::new().load(path).unwrap_or_default() | ||||
| } | ||||
| 
 | ||||
| fn load_data(root: &Path, path: &Path) -> Result<Value> { | ||||
|     let full_path = &root.join(path); | ||||
|     let emi_path = full_path.join("map").join("map3d.emi"); | ||||
|     let sm3_path = emi_path.with_extension("sm3"); | ||||
|     let dum_path = emi_path.with_extension("dum"); | ||||
|     let config_file = emi_path.with_extension("ini"); | ||||
|     let moredummies = emi_path.with_file_name("moredummies").with_extension("ini"); | ||||
|     let mut data = serde_json::to_value(HashMap::<(), ()>::default())?; | ||||
|     data["config"] = serde_json::to_value(load_ini(&config_file))?; | ||||
|     data["moredummies"] = serde_json::to_value(load_ini(&moredummies))?; | ||||
|     data["emi"] = serde_json::to_value(parse_file(&emi_path)?)?; | ||||
|     data["sm3"] = serde_json::to_value(parse_file(&sm3_path)?)?; | ||||
|     data["dummies"] = serde_json::to_value(parse_file(&dum_path)?)?; | ||||
|     data["path"] = serde_json::to_value(path)?; | ||||
|     data["root"] = serde_json::to_value(root)?; | ||||
|     Ok(data) | ||||
| } | ||||
| 
 | ||||
| fn main() -> Result<()> { | ||||
|     let args = Args::try_parse()?; | ||||
|     let out_path = PathBuf::from( | ||||
|         args.path | ||||
|             .components() | ||||
|             .last() | ||||
|             .unwrap() | ||||
|             .as_os_str() | ||||
|             .to_string_lossy() | ||||
|             .into_owned(), | ||||
|     ) | ||||
|     .with_extension("json.gz"); | ||||
|     let full_path = &args.root.join(&args.path); | ||||
|     let data = if full_path.is_dir() { | ||||
|         load_data(&args.root, &args.path)? | ||||
|     } else { | ||||
|         serde_json::to_value(parse_file(full_path)?)? | ||||
|     }; | ||||
|     let mut dumpfile = GzEncoder::new(File::create(&out_path)?, Compression::best()); | ||||
|     serde_json::to_writer_pretty(&mut dumpfile, &data)?; | ||||
|     println!("Wrote {path}", path = out_path.display()); | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										26
									
								
								tools/remaster/scrap_parse/src/pixel_shader.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tools/remaster/scrap_parse/src/pixel_shader.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| // #[derive(Debug)]
 | ||||
| // enum VecArg {
 | ||||
| //     Tex(f32,f32,f32,f32),
 | ||||
| //     Reg(f32,f32,f32,f32),
 | ||||
| //     Ver(f32,f32,f32,f32),
 | ||||
| //     Col(f32,f32,f32,f32),
 | ||||
| //     Vec(f32,f32,f32,f32),
 | ||||
| // }
 | ||||
| 
 | ||||
| // struct Arg {
 | ||||
| //     arg: VecArg,
 | ||||
| //     idx: Option<usize>
 | ||||
| // }
 | ||||
| 
 | ||||
| // #[derive(Debug)]
 | ||||
| // enum Inst {
 | ||||
| //     Tex(Arg),
 | ||||
| //     Add(Arg,Arg,Arag),
 | ||||
| //     Sub(Arg,Arg,Arag),
 | ||||
| //     Mul(Arg,Arg,Arag),
 | ||||
| //     Mov(Arg,Arg),
 | ||||
| // }
 | ||||
| 
 | ||||
| fn parse(path: &str) { | ||||
|     
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue