Last active
September 19, 2021 08:42
-
-
Save TheDucker1/974e61c5adce281643c345f12c13a0bd to your computer and use it in GitHub Desktop.
unswizzled chara texture data in the game Yahari Game demo Ore no Seishun Love Come wa Machigatteiru.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #unswizzled texture data in the game Yahari Game demo Ore no Seishun Love Come wa Machigatteiru. | |
| #for some reason the game didn't use the float encode for src_x and src_y like in https://github.com/AbsurdlySuspicious/sg-sprite/blob/master/lay-format.md | |
| import cv2 | |
| import struct | |
| import numpy as np | |
| #i think the x and y use some mapping algorithm, but for now i will use a look up table | |
| x_table = { #width = 2048 --> 64 x_chunks | |
| 0x3A000000: 0, | |
| 0x3C840000: 1, | |
| 0x3D020000: 2, | |
| 0x3D420000: 3, | |
| 0x3D810000: 4, | |
| 0x3DA10000: 5, | |
| 0x3DC10000: 6, | |
| 0x3DE10000: 7, | |
| 0x3E008000: 8, | |
| 0x3E108000: 9, | |
| 0x3E208000: 10, | |
| 0x3E308000: 11, | |
| 0x3E408000: 12, | |
| 0x3E508000: 13, | |
| 0x3E608000: 14, | |
| 0x3E708000: 15, | |
| 0x3E804000: 16, | |
| 0x3E884000: 17, | |
| 0x3E904000: 18, | |
| 0x3E984000: 19, | |
| 0x3EA04000: 20, | |
| 0x3EA84000: 21, | |
| 0x3EB04000: 22, | |
| 0x3EB84000: 23, | |
| 0x3EC04000: 24, | |
| 0x3EC84000: 25, | |
| 0x3ED04000: 26, | |
| 0x3ED84000: 27, | |
| 0x3EE04000: 28, | |
| 0x3EE84000: 29, | |
| 0x3EF04000: 30, | |
| 0x3EF84000: 31, | |
| 0x3F002000: 32, | |
| 0x3F042000: 33, | |
| 0x3F082000: 34, | |
| 0x3F0C2000: 35, | |
| 0x3F102000: 36, | |
| 0x3F142000: 37, | |
| 0x3F182000: 38, | |
| 0x3F1C2000: 39, | |
| 0x3F202000: 40, | |
| 0x3F242000: 41, | |
| 0x3F282000: 42, | |
| 0x3F2C2000: 43, | |
| 0x3F302000: 44, | |
| 0x3F342000: 45, | |
| 0x3F382000: 46, | |
| 0x3F3C2000: 47, | |
| 0x3F402000: 48, | |
| 0x3F442000: 49, | |
| 0x3F482000: 50, | |
| 0x3F4C2000: 51, | |
| 0x3F502000: 52, | |
| 0x3F542000: 53, | |
| 0x3F582000: 54, | |
| 0x3F5C2000: 55, | |
| 0x3F602000: 56, | |
| 0x3F642000: 57, | |
| 0x3F682000: 58, | |
| 0x3F6C2000: 59, | |
| 0x3F702000: 60, | |
| 0x3F742000: 61, | |
| 0x3F782000: 62, | |
| 0x3F7C2000: 63, | |
| } | |
| y_table = { #height = 1024 --> 32 y_chunks | |
| 0x3A800000: 0, | |
| 0x3D040000: 1, | |
| 0x3D820000: 2, | |
| 0x3DC20000: 3, | |
| 0x3E010000: 4, | |
| 0x3E210000: 5, | |
| 0x3E410000: 6, | |
| 0x3E610000: 7, | |
| 0x3E808000: 8, | |
| 0x3E908000: 9, | |
| 0x3EA08000: 10, | |
| #below is what i guess, not taken from any file, may be incorrect so need further test | |
| 0x3EB08000: 11, | |
| 0x3EC08000: 12, | |
| 0x3ED08000: 13, | |
| 0x3EE08000: 14, | |
| 0x3EF08000: 15, | |
| 0x3F004000: 16, | |
| 0x3F084000: 17, | |
| 0x3F104000: 18, | |
| 0x3F184000: 19, | |
| 0x3F204000: 20, | |
| 0x3F284000: 21, | |
| 0x3F304000: 22, | |
| 0x3F384000: 23, | |
| 0x3F404000: 24, | |
| 0x3F484000: 25, | |
| 0x3F504000: 26, | |
| 0x3F584000: 27, | |
| 0x3F604000: 28, | |
| 0x3F684000: 29, | |
| 0x3F704000: 30, | |
| 0x3F784000: 31, | |
| } | |
| tex_png = '.\\output\\0124' #gxt file, converted to png so cv2 can read | |
| lay = '.\\output\\0125' #the file that goes right next to the gxt file | |
| src_im = cv2.imread(tex_png, cv2.IMREAD_UNCHANGED) | |
| f = open(lay, 'rb') | |
| lay_dat = bytearray(f.read()) | |
| f.close() | |
| #init | |
| sprite_count = struct.unpack('<I', lay_dat[0: 4])[0] | |
| chunk_count = struct.unpack('<I', lay_dat[4: 8])[0] | |
| sprite_start = 0x8 | |
| sprite_length = 0xC * sprite_count | |
| chunk_start = sprite_start + sprite_length | |
| chunk_length = chunk_count * 0x10 | |
| print(sprite_count, chunk_count) | |
| min_x = 0 | |
| max_x = 0 | |
| min_y = 0 | |
| max_y = 0 | |
| for i in range(chunk_count): | |
| dst_x, dst_y = struct.unpack('<2f', lay_dat[chunk_start + i * 0x10 : chunk_start + i * 0x10 + 8]) | |
| dst_x, dst_y = int(dst_x), int(dst_y) | |
| min_x = min(min_x, dst_x) | |
| max_x = max(max_x, dst_x + 32) | |
| min_y = min(min_y, dst_y) | |
| max_y = max(max_y, dst_y + 32) | |
| x_offset = -min_x | |
| y_offset = -min_y | |
| w, h = max_x - min_x, max_y - min_y | |
| del min_x, max_x, min_y, max_y | |
| print(w, h) | |
| sprites_raw = [] | |
| #refer to https://github.com/AbsurdlySuspicious/sg-sprite/blob/master/lay-format.md | |
| for i in range(sprite_count): #generate sprite | |
| sprites_raw.append(np.zeros((h, w, 4), np.uint8)) | |
| #read sprite info | |
| s_a, s_b, s_c, s_d = struct.unpack('<4B', lay_dat[sprite_start + i * 0xC : sprite_start + i * 0xC + 4]) | |
| #skip for now | |
| s_chunk_offset, s_chunk_count = struct.unpack('<2I', lay_dat[sprite_start + i * 0xC + 4 : sprite_start + i * 0xC + 12]) | |
| s_chunk_offset *= 0x10 | |
| for c in range(s_chunk_count): | |
| c_dst_x, c_dst_y = struct.unpack('<2f', lay_dat[chunk_start + s_chunk_offset + c * 0x10 : chunk_start + s_chunk_offset + c * 0x10 + 8]) | |
| c_dst_x, c_dst_y = int(c_dst_x) + x_offset, int(c_dst_y) + y_offset | |
| chunk_x, chunk_y = struct.unpack('<2I', lay_dat[chunk_start + s_chunk_offset + c * 0x10 + 8: chunk_start + s_chunk_offset + c * 0x10 + 16]) | |
| #print(hex(chunk_x), hex(chunk_y)) | |
| chunk_x, chunk_y = x_table[chunk_x], y_table[chunk_y] | |
| #print(chunk_x, chunk_y) | |
| sprites_raw[i][c_dst_y : c_dst_y + 32, c_dst_x : c_dst_x + 32, :] = \ | |
| src_im[chunk_y * 32 : chunk_y * 32 + 32, chunk_x * 32 : chunk_x * 32 + 32, :] | |
| #could generate layered images (TIFF?), but i will just let it show the layers here | |
| cv2.imshow('', sprites_raw[i]) | |
| cv2.waitKey(0) | |
| cv2.destroyAllWindows() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment