forked from MooncellWiki/UnityPy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTextureSwizzler.py
More file actions
137 lines (120 loc) · 5.22 KB
/
Copy pathTextureSwizzler.py
File metadata and controls
137 lines (120 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# based on https://github.com/nesrak1/UABEA/blob/master/TexturePlugin/Texture2DSwitchDeswizzler.cs
from typing import Dict, Tuple
from ..enums import TextureFormat
GOB_X_TEXEL_COUNT = 4
GOB_Y_TEXEL_COUNT = 8
TEXEL_BYTE_SIZE = 16
TEXELS_IN_GOB = GOB_X_TEXEL_COUNT * GOB_Y_TEXEL_COUNT
GOB_MAP = [
(((l >> 3) & 0b10) | ((l >> 1) & 0b1), ((l >> 1) & 0b110) | (l & 0b1))
for l in range(TEXELS_IN_GOB)
]
def ceil_divide(a: int, b: int) -> int:
return (a + b - 1) // b
def deswizzle(
data: bytes,
width: int,
height: int,
block_width: int,
block_height: int,
texels_per_block: int,
) -> bytearray:
block_count_x = ceil_divide(width, block_width)
block_count_y = ceil_divide(height, block_height)
gob_count_x = block_count_x // GOB_X_TEXEL_COUNT
gob_count_y = block_count_y // GOB_Y_TEXEL_COUNT
new_data = bytearray(len(data))
data_view = memoryview(data)
for i in range(gob_count_y // texels_per_block):
for j in range(gob_count_x):
base_gob_dst_x = j * 4
for k in range(texels_per_block):
base_gob_dst_y = (i * texels_per_block + k) * GOB_Y_TEXEL_COUNT
for gob_x, gob_y in GOB_MAP:
dst_offset = (
(base_gob_dst_y + gob_y) * block_count_x
+ (base_gob_dst_x + gob_x)
) * TEXEL_BYTE_SIZE
new_data[dst_offset : dst_offset + TEXEL_BYTE_SIZE] = data_view[
:TEXEL_BYTE_SIZE
]
data_view = data_view[TEXEL_BYTE_SIZE:]
return new_data
def swizzle(
data: bytes,
width: int,
height: int,
block_width: int,
block_height: int,
texels_per_block: int,
) -> bytearray:
block_count_x = ceil_divide(width, block_width)
block_count_y = ceil_divide(height, block_height)
gob_count_x = block_count_x // GOB_X_TEXEL_COUNT
gob_count_y = block_count_y // GOB_Y_TEXEL_COUNT
new_data = bytearray(len(data))
data_view = memoryview(new_data)
for i in range(gob_count_y // texels_per_block):
for j in range(gob_count_x):
base_gob_dst_x = j * 4
for k in range(texels_per_block):
base_gob_dst_y = (i * texels_per_block + k) * GOB_Y_TEXEL_COUNT
for gob_x, gob_y in GOB_MAP:
src_offset = (
(base_gob_dst_y + gob_y) * block_count_x
+ (base_gob_dst_x + gob_x)
) * TEXEL_BYTE_SIZE
data_view[:TEXEL_BYTE_SIZE] = data[
src_offset : src_offset + TEXEL_BYTE_SIZE
]
data_view = data_view[TEXEL_BYTE_SIZE:]
return new_data
# this should be the amount of pixels that can fit 16 bytes
TEXTUREFORMAT_BLOCK_SIZE_MAP: Dict[TextureFormat, Tuple[int, int]] = {
TextureFormat.Alpha8: (16, 1), # 1 byte per pixel
TextureFormat.ARGB4444: (8, 1), # 2 bytes per pixel
TextureFormat.RGBA32: (4, 1), # 4 bytes per pixel
TextureFormat.ARGB32: (4, 1), # 4 bytes per pixel
TextureFormat.ARGBFloat: (1, 1), # 16 bytes per pixel (?)
TextureFormat.RGB565: (8, 1), # 2 bytes per pixel
TextureFormat.R16: (8, 1), # 2 bytes per pixel
TextureFormat.DXT1: (8, 4), # 8 bytes per 4x4=16 pixels
TextureFormat.DXT5: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.RGBA4444: (8, 1), # 2 bytes per pixel
TextureFormat.BGRA32: (4, 1), # 4 bytes per pixel
TextureFormat.BC6H: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.BC7: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.BC4: (8, 4), # 8 bytes per 4x4=16 pixels
TextureFormat.BC5: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.ASTC_RGB_4x4: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.ASTC_RGB_5x5: (5, 5), # 16 bytes per 5x5=25 pixels
TextureFormat.ASTC_RGB_6x6: (6, 6), # 16 bytes per 6x6=36 pixels
TextureFormat.ASTC_RGB_8x8: (8, 8), # 16 bytes per 8x8=64 pixels
TextureFormat.ASTC_RGB_10x10: (10, 10), # 16 bytes per 10x10=100 pixels
TextureFormat.ASTC_RGB_12x12: (12, 12), # 16 bytes per 12x12=144 pixels
TextureFormat.ASTC_RGBA_4x4: (4, 4), # 16 bytes per 4x4=16 pixels
TextureFormat.ASTC_RGBA_5x5: (5, 5), # 16 bytes per 5x5=25 pixels
TextureFormat.ASTC_RGBA_6x6: (6, 6), # 16 bytes per 6x6=36 pixels
TextureFormat.ASTC_RGBA_8x8: (8, 8), # 16 bytes per 8x8=64 pixels
TextureFormat.ASTC_RGBA_10x10: (10, 10), # 16 bytes per 10x10=100 pixels
TextureFormat.ASTC_RGBA_12x12: (12, 12), # 16 bytes per 12x12=144 pixels
TextureFormat.RG16: (8, 1), # 2 bytes per pixel
TextureFormat.R8: (16, 1), # 1 byte per pixel
}
def get_padded_texture_size(
width: int, height: int, block_width: int, block_height: int, texels_per_block: int
):
width = (
ceil_divide(width, block_width * GOB_X_TEXEL_COUNT)
* block_width
* GOB_X_TEXEL_COUNT
)
height = (
ceil_divide(height, block_height * GOB_Y_TEXEL_COUNT * texels_per_block)
* block_height
* GOB_Y_TEXEL_COUNT
* texels_per_block
)
return width, height
def get_switch_gobs_per_block(platform_blob: bytes) -> int:
return 1 << int.from_bytes(platform_blob[8:12], "little")