forked from beyond-all-reason/OBJ2S3O
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paths3o-optimize.py
121 lines (94 loc) · 3.68 KB
/
s3o-optimize.py
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
#!/usr/bin/env python
from s3o import S3O
from optparse import OptionParser
from glob import glob
import vertex_cache
def recursively_optimize_pieces(piece):
optimize_piece(piece)
for child in piece.children:
recursively_optimize_pieces(child)
def chunks(l, n):
""" Yield successive n-sized chunks from l.
"""
for i in range(0, len(l), n):
yield tuple(l[i:i + n])
def optimize_piece(piece):
remap = {}
new_indices = []
for index in piece.indices:
vertex = piece.vertices[index]
if vertex not in remap:
remap[vertex] = len(remap)
new_indices.append(remap[vertex])
new_vertices = [(index, vertex) for vertex, index in remap.items()]
new_vertices.sort()
new_vertices = [vertex for index, vertex in new_vertices]
if piece.primitive_type == "triangles" and len(new_indices) > 0:
tris = list(chunks(new_indices, 3))
acmr = vertex_cache.average_transform_to_vertex_ratio(tris)
tmp = vertex_cache.get_cache_optimized_triangles(tris)
acmr_new = vertex_cache.average_transform_to_vertex_ratio(tmp)
if acmr_new < acmr:
new_indices = []
for tri in tmp:
new_indices.extend(tri)
vertex_map = []
remapped_indices = []
for index in new_indices:
try:
new_index = vertex_map.index(index)
except ValueError:
new_index = len(vertex_map)
vertex_map.append(index)
remapped_indices.append(new_index)
new_vertices = [new_vertices[index] for index in vertex_map]
new_indices = remapped_indices
piece.indices = new_indices
piece.vertices = new_vertices
def sizeof_fmt(num):
for x in ['bytes', 'KB', 'MB', 'GB']:
if abs(num) < 1024.0:
return "%3.1f %s" % (num, x)
num /= 1024.0
return "%3.1f%s" % (num, 'TB')
if __name__ == '__main__':
parser = OptionParser(usage="%prog [options] FILES", version="%prog 0.1",
description="Optimize a Spring S3O file by "
"removing redundant data.")
parser.add_option("-d", "--dry-run", action="store_true",
default=False, dest="is_dry",
help="show output summary without committing changes")
parser.add_option("-q", "--quiet", action="store_true",
default=False, dest="silence_output",
help="silence detailed optimization output")
options, args = parser.parse_args()
if len(args) < 1:
parser.error("insufficient arguments")
dry = options.is_dry
silence_output = options.silence_output
if len(args) == 1:
filenames = glob(args[0])
else:
filenames = args
delta_total = 0
for filename in filenames:
with open(filename, 'rb+') as input_file:
data = input_file.read()
model = S3O(data)
recursively_optimize_pieces(model.root_piece)
optimized_data = model.serialize()
delta_size = len(optimized_data) - len(data)
if delta_size <= 0:
delta_total += delta_size
if not silence_output:
print("modified %s: "
"size change: %d bytes" % (filename, delta_size))
if not dry:
input_file.seek(0)
input_file.truncate()
input_file.write(optimized_data)
else:
if not silence_output:
print("not modified %s: "
"size change: %d bytes" % (filename, delta_size))
print("total size difference: %s" % sizeof_fmt(delta_total))