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