Skip to content

Commit dd7fae7

Browse files
Matrix Bank, Matrix2x3, Movie Clip rendering
1 parent 0706fa7 commit dd7fae7

21 files changed

+560
-267
lines changed

.gitignore

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
/SC/
2-
/CSV/
3-
/updates/
1+
# IDE project files
42
/.idea/
3+
/*.iml
4+
5+
# Script folders
6+
/updates/
57
/logs/
8+
/CSV/
9+
/SC/
10+
11+
# Configuration files
612
system/config.json
13+
14+
# Python compiled files
715
*.pyc

system/bytestream.py

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,69 @@
11
import io
2+
from typing import Literal
23

34

45
class Reader(io.BytesIO):
5-
def __init__(self, buffer: bytes = b'', endian: str = 'little'):
6+
def __init__(self, buffer: bytes = b'', endian: Literal['little', 'big'] = 'little'):
67
super().__init__(buffer)
8+
79
self.buffer = buffer
810
self.endian = endian
911

10-
def read_int(self, length: int, signed=False):
12+
def read_integer(self, length: int, signed=False) -> int:
1113
return int.from_bytes(self.read(length), self.endian, signed=signed)
1214

13-
def read_ubyte(self):
14-
return self.read_int(1)
15+
def read_uchar(self) -> int:
16+
return self.read_integer(1)
17+
18+
def read_char(self) -> int:
19+
return self.read_integer(1, True)
1520

16-
def read_byte(self):
17-
return self.read_int(1, True)
21+
def read_ushort(self) -> int:
22+
return self.read_integer(2)
1823

19-
def read_uint16(self):
20-
return self.read_int(2)
24+
def read_short(self) -> int:
25+
return self.read_integer(2, True)
2126

22-
def read_int16(self):
23-
return self.read_int(2, True)
27+
def read_uint(self) -> int:
28+
return self.read_integer(4)
2429

25-
def read_uint32(self):
26-
return self.read_int(4)
30+
def read_int(self) -> int:
31+
return self.read_integer(4, True)
2732

28-
def read_int32(self):
29-
return self.read_int(4, True)
33+
def read_twip(self) -> float:
34+
return self.read_int() / 20
3035

31-
def read_string(self):
32-
length = self.read_ubyte()
36+
def read_string(self) -> str:
37+
length = self.read_uchar()
3338
if length != 255:
3439
return self.read(length).decode()
3540
return ''
3641

3742

3843
class Writer(io.BytesIO):
39-
def __init__(self, endian: str = 'little'):
44+
def __init__(self, endian: Literal['little', 'big'] = 'little'):
4045
super().__init__()
4146
self.endian = endian
4247

43-
def write_int(self, integer, length: int = 1, signed: bool = False):
48+
def write_int(self, integer: int, length: int = 1, signed: bool = False):
4449
self.write(integer.to_bytes(length, self.endian, signed=signed))
4550

46-
def write_ubyte(self, integer):
51+
def write_ubyte(self, integer: int):
4752
self.write_int(integer)
4853

49-
def write_byte(self, integer):
54+
def write_byte(self, integer: int):
5055
self.write_int(integer, signed=True)
5156

52-
def write_uint16(self, integer):
57+
def write_uint16(self, integer: int):
5358
self.write_int(integer, 2)
5459

55-
def write_int16(self, integer):
60+
def write_int16(self, integer: int):
5661
self.write_int(integer, 2, True)
5762

58-
def write_uint32(self, integer):
63+
def write_uint32(self, integer: int):
5964
self.write_int(integer, 4)
6065

61-
def write_int32(self, integer):
66+
def write_int32(self, integer: int):
6267
self.write_int(integer, 4, True)
6368

6469
def write_string(self, string: str = None):

system/lib/__init__.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414

1515
logger.remove()
1616
logger.add(
17-
'./logs/info/{time:YYYY-DD-MM}.log',
17+
'./logs/info/{time:YYYY-MM-DD}.log',
1818
format='[{time:HH:mm:ss}] [{level}]: {message}',
1919
encoding="utf8",
2020
level='INFO'
2121
)
2222
logger.add(
23-
'./logs/errors/{time:YYYY-DD-MM}.log',
23+
'./logs/errors/{time:YYYY-MM-DD}.log',
2424
format='[{time:HH:mm:ss}] [{level}]: {message}',
2525
backtrace=True,
2626
diagnose=True,
@@ -34,6 +34,7 @@
3434

3535

3636
try:
37+
# noinspection PyUnresolvedReferences
3738
import requests
3839
del requests
3940

@@ -58,6 +59,7 @@
5859
pass
5960

6061

62+
# noinspection PyUnresolvedReferences
6163
@logger.catch()
6264
def refill_menu():
6365
menu.categories.clear()
@@ -73,10 +75,10 @@ def refill_menu():
7375
import PIL
7476
del PIL
7577

76-
from system.lib.features.sc.assembly_encode import sc1_encode
7778
from system.lib.features.sc.decode import sc_decode
78-
from system.lib.features.sc.decode_and_cut import sc1_decode
79-
from system.lib.features.sc.sc_encode import sc_encode
79+
from system.lib.features.sc.encode import sc_encode
80+
from system.lib.features.sc.decode_and_cut import decode_and_cut
81+
from system.lib.features.sc.assembly_encode import sc1_encode
8082

8183
sc_category = Menu.Category(0, locale.sc_label)
8284
sc_category.add(Menu.Item(
@@ -92,7 +94,7 @@ def refill_menu():
9294
sc_category.add(Menu.Item(
9395
locale.decode_by_parts,
9496
locale.decode_by_parts_description,
95-
sc1_decode
97+
decode_and_cut
9698
))
9799
sc_category.add(Menu.Item(
98100
locale.encode_by_parts,

system/lib/features/cut_sprites.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,55 @@
88
def cut_sprites(swf: SupercellSWF, export_folder: str):
99
os.makedirs(f'{export_folder}/overwrite', exist_ok=True)
1010
os.makedirs(f'{export_folder}/shapes', exist_ok=True)
11+
os.makedirs(f'{export_folder}/movie_clips', exist_ok=True)
12+
13+
# TODO: Too slow, fix it
14+
# movie_clips_skipped = 0
15+
# movie_clip_count = len(swf.movie_clips)
16+
# for movie_clip_index in range(movie_clip_count):
17+
# movie_clip = swf.movie_clips[movie_clip_index]
18+
#
19+
# rendered_movie_clip = movie_clip.render(swf)
20+
# if sum(rendered_movie_clip.size) >= 2:
21+
# rendered_movie_clip.save(f'{export_folder}/movie_clips/{movie_clip.export_name or movie_clip.id}.png')
22+
# else:
23+
# # For debug:
24+
# # logger.warning(f'MovieClip {movie_clip.id} cannot be rendered.')
25+
# movie_clips_skipped += 1
26+
#
27+
# Console.progress_bar(
28+
# 'Rendering movie clips (%d/%d). Skipped count: %d' %
29+
# (movie_clip_index + 1, movie_clip_count, movie_clips_skipped),
30+
# movie_clip_index,
31+
# movie_clip_count
32+
# )
1133

1234
shapes_count = len(swf.shapes)
1335
swf.xcod_writer.write_uint16(shapes_count)
1436

1537
for shape_index in range(shapes_count):
38+
shape = swf.shapes[shape_index]
39+
1640
Console.progress_bar(
1741
locale.cut_sprites_process % (shape_index + 1, shapes_count),
1842
shape_index,
1943
shapes_count
2044
)
2145

22-
shape = swf.shapes[shape_index]
23-
24-
rendered_shape = shape.render(swf)
46+
rendered_shape = shape.render()
2547
rendered_shape.save(f'{export_folder}/shapes/{shape.id}.png')
2648

49+
regions_count = len(shape.regions)
50+
for region_index in range(regions_count):
51+
region = shape.regions[region_index]
52+
53+
region.apply_matrix(None)
54+
rendered_region = region.render()
55+
rendered_region.save(f'{export_folder}/shape_{shape.id}_{region_index}.png')
56+
57+
for shape_index in range(shapes_count):
58+
shape = swf.shapes[shape_index]
59+
2760
regions_count = len(shape.regions)
2861
swf.xcod_writer.write_uint16(shape.id)
2962
swf.xcod_writer.write_uint16(regions_count)
@@ -38,6 +71,3 @@ def cut_sprites(swf: SupercellSWF, export_folder: str):
3871
swf.xcod_writer.write_uint16(int(region.get_v(i)))
3972
swf.xcod_writer.write_ubyte(1 if region.is_mirrored else 0)
4073
swf.xcod_writer.write_byte(region.rotation // 90)
41-
42-
rendered_region = region.render(swf)
43-
rendered_region.save(f'{export_folder}/shape_{shape.id}_{region_index}.png')

system/lib/features/place_sprites.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ def place_sprites(xcod_path: str, folder: str, overwrite: bool = False) -> (list
2424
Image.new(get_format_by_pixel_type(sheet_info.pixel_type), sheet_info.size)
2525
)
2626

27-
shapes_count = xcod.read_uint16()
27+
shapes_count = xcod.read_ushort()
2828
for shape_index in range(shapes_count):
2929
Console.progress_bar(locale.place_sprites_process % (shape_index + 1, shapes_count), shape_index, shapes_count)
30-
shape_id = xcod.read_uint16()
30+
shape_id = xcod.read_ushort()
3131

32-
regions_count = xcod.read_uint16()
32+
regions_count = xcod.read_ushort()
3333
for region_index in range(regions_count):
34-
texture_id, points_count = xcod.read_ubyte(), xcod.read_ubyte()
34+
texture_id, points_count = xcod.read_uchar(), xcod.read_uchar()
3535
texture_width, texture_height = sheets[texture_id].width, sheets[texture_id].height
36-
polygon = [(xcod.read_uint16(), xcod.read_uint16()) for _ in range(points_count)]
37-
mirroring, rotation = xcod.read_ubyte() == 1, xcod.read_byte() * 90
36+
polygon = [(xcod.read_ushort(), xcod.read_ushort()) for _ in range(points_count)]
37+
mirroring, rotation = xcod.read_uchar() == 1, xcod.read_char() * 90
3838

3939
filename = f'shape_{shape_id}_{region_index}.png'
4040
if filename not in files_to_overwrite:

system/lib/features/sc/decode_and_cut.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from system.localization import locale
99

1010

11-
def sc1_decode():
11+
def decode_and_cut():
1212
input_folder = './SC/In-Compressed'
1313
output_folder = './SC/Out-Sprites'
1414
files = os.listdir(input_folder)

system/lib/helper.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from typing import List, Tuple
2+
3+
from system.lib.objects.point import Point
4+
5+
6+
def get_size(left: float, top: float, right: float, bottom: float) -> (int, int):
7+
"""Returns width and height of given rect.
8+
9+
:param left: left side of polygon
10+
:param top: top side of polygon
11+
:param right: right side of polygon
12+
:param bottom: bottom side of polygon
13+
:return: width, height
14+
"""
15+
return int(right - left), int(bottom - top)
16+
17+
18+
def get_sides(points: List[Tuple[float, float]] or List[Point]) -> (float, float, float, float):
19+
"""Calculates and returns rect sides.
20+
21+
:param points: polygon points
22+
:return: left, top, right, bottom
23+
"""
24+
if len(points) > 0:
25+
point = points[0]
26+
if isinstance(point, Point):
27+
left = min(point.x for point in points)
28+
top = min(point.y for point in points)
29+
right = max(point.x for point in points)
30+
bottom = max(point.y for point in points)
31+
elif isinstance(point, tuple):
32+
left = min(x for x, _ in points)
33+
top = min(y for _, y in points)
34+
right = max(x for x, _ in points)
35+
bottom = max(y for _, y in points)
36+
else:
37+
raise TypeError('Unknown point type.')
38+
39+
return left, top, right, bottom
40+
raise ValueError('Empty points list.')

system/lib/images.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,31 @@ def load_texture(data: Reader, _type, img):
108108
channels_count = 4
109109
if _type in (0, 1):
110110
def read_pixel():
111-
return data.read_ubyte(), data.read_ubyte(), data.read_ubyte(), data.read_ubyte()
111+
return data.read_uchar(), data.read_uchar(), data.read_uchar(), data.read_uchar()
112112
elif _type == 2:
113113
def read_pixel():
114-
p = data.read_uint16()
114+
p = data.read_ushort()
115115
return (p >> 12 & 15) << 4, (p >> 8 & 15) << 4, (p >> 4 & 15) << 4, (p >> 0 & 15) << 4
116116
elif _type == 3:
117117
def read_pixel():
118-
p = data.read_uint16()
118+
p = data.read_ushort()
119119
return (p >> 11 & 31) << 3, (p >> 6 & 31) << 3, (p >> 1 & 31) << 3, (p & 255) << 7
120120
elif _type == 4:
121121
channels_count = 3
122122

123123
def read_pixel():
124-
p = data.read_uint16()
124+
p = data.read_ushort()
125125
return (p >> 11 & 31) << 3, (p >> 5 & 63) << 2, (p & 31) << 3
126126
elif _type == 6:
127127
channels_count = 2
128128

129129
def read_pixel():
130-
return (data.read_ubyte(), data.read_ubyte())[::-1]
130+
return (data.read_uchar(), data.read_uchar())[::-1]
131131
elif _type == 10:
132132
channels_count = 1
133133

134134
def read_pixel():
135-
return data.read_ubyte()
135+
return data.read_uchar()
136136

137137
if read_pixel is None:
138138
return

system/lib/matrices/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)