Skip to content

Instantly share code, notes, and snippets.

@TheDucker1
Last active September 19, 2021 08:42
Show Gist options
  • Select an option

  • Save TheDucker1/974e61c5adce281643c345f12c13a0bd to your computer and use it in GitHub Desktop.

Select an option

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.
#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