Commit | Line | Data |
---|---|---|
8ee66edd FC |
1 | '''Provides tools for building models.''' |
2 | from logging import info | |
3 | from os import system, walk, makedirs | |
e65a09cf | 4 | from os.path import exists, dirname |
218c8938 | 5 | from multiprocessing import Pool |
8ee66edd | 6 | from hashlib import md5 |
e65a09cf | 7 | from shutil import copyfile, rmtree |
53ddf3c3 | 8 | from ya2.build.build import to_be_built |
8ee66edd FC |
9 | |
10 | ||
11 | class ModelsBuilder(): | |
12 | ||
13 | def __init__(self): | |
14 | self._cache_files = [] # for avoiding rebuilding the same file | |
15 | ||
16 | def build(self, blend_path, cores): | |
17 | '''Builds the models i.e. creates glTF and bam files from blend | |
18 | ones.''' | |
218c8938 | 19 | args = [] |
8ee66edd | 20 | for root, _, fnames in walk(blend_path): |
e65a09cf FC |
21 | blends = [fname for fname in fnames if fname.endswith('.blend')] |
22 | for fname in blends: | |
8ee66edd | 23 | if '/prototypes/' not in root: |
218c8938 FC |
24 | args += [(root, fname)] |
25 | with Pool() as p: | |
26 | p.starmap(self._export_blend, args) | |
27 | # caching is broken now: it is based on the previous | |
28 | # non-multiprocessing approach | |
e65a09cf FC |
29 | # i should evaluate if fix it or just change the blend_path for |
30 | # building only specific models | |
8ee66edd FC |
31 | cache, lines = [], [] |
32 | if exists('hash_cache.txt'): | |
33 | with open('hash_cache.txt') as fhash: | |
34 | lines = fhash.readlines() | |
35 | for line in lines: # line's e.g. assets/path/to/gltf_or_png.ext 68ced1 | |
36 | line_spl = line.split() | |
37 | hashval = line_spl[-1] | |
38 | fname = ' '.join(line_spl[:-1]) | |
39 | if fname not in self._cache_files: | |
40 | cache += [(fname, hashval)] | |
41 | for cfile in self._cache_files: | |
42 | cache += [(cfile, md5(open(cfile, 'rb').read()).hexdigest())] | |
43 | cache = cache[-2048:] | |
44 | with open('hash_cache.txt', 'w') as fhash: | |
45 | fhash.write('\n'.join([' '.join(line) for line in cache])) | |
46 | ||
218c8938 | 47 | def _export_blend(self, root, fname): |
8ee66edd FC |
48 | '''Exports blend files to glTF and bam formats.''' |
49 | if self._export_gltf(root, fname): | |
218c8938 | 50 | self._export_bam(root, fname) |
8ee66edd FC |
51 | |
52 | def _export_gltf(self, root, fname): | |
53 | '''Exports glTF files from blend ones.''' | |
54 | _fname = '%s/%s' % (root, fname) | |
218c8938 FC |
55 | pgltf = 'assets/models/gltf/' |
56 | new_dir = root.replace('assets/models/blend/', pgltf) | |
57 | rmtree(new_dir, ignore_errors=True) | |
58 | makedirs(new_dir) | |
e65a09cf | 59 | # files_before = [basename(gname) for gname in glob('./*')] |
53ddf3c3 | 60 | cmd = 'blender %s --background --python ya2/build/blend2gltf.py ' |
8ee66edd | 61 | cmd += '-- %s.gltf' |
218c8938 | 62 | cmd = cmd % (_fname, new_dir + '/' + fname[:-6]) |
420ce99a | 63 | gltf_name = _fname.replace('assets/models/blend/', pgltf) |
8ee66edd FC |
64 | gltf_name = gltf_name.replace('.blend', '.gltf') |
65 | if not to_be_built(gltf_name, [_fname]): | |
66 | return False | |
67 | system(cmd) | |
68 | self._cache_files += [_fname, gltf_name] | |
e65a09cf FC |
69 | # files_after = [basename(gname) for gname in glob('./*')] |
70 | # new_files = [nnm for nnm in files_after if nnm not in files_before] | |
71 | # new_dir = root.replace('assets/models/blend/', pgltf) | |
72 | # rmtree(new_dir, ignore_errors=True) | |
73 | # makedirs(new_dir) | |
74 | # for mname in new_files: | |
75 | # new_name = '%s/%s' % (new_dir, mname) | |
76 | # move(mname, new_name) | |
77 | # info('move %s %s' % (mname, new_name)) | |
420ce99a FC |
78 | # # blender rewrites metal files: let's restore them |
79 | # metal_files = [fnm for fnm in glob(new_dir + '/*') if 'metal' in fnm] | |
80 | # for metal_file in metal_files: | |
81 | # src = metal_file.replace(pgltf, 'assets/models/') | |
82 | # if not exists(src): | |
83 | # src = metal_file.replace(pgltf, 'assets/models/prototypes/') | |
84 | # src_split = src.split('/') | |
85 | # src_tracks_idx = src_split.index('tracks') | |
86 | # before = src_split[:src_tracks_idx] | |
87 | # after = src_split[src_tracks_idx + 2:] | |
88 | # src = '/'.join(before + after) | |
89 | # copyfile(src, metal_file) | |
8ee66edd FC |
90 | return True |
91 | ||
218c8938 | 92 | def _export_bam(self, root, fname): |
8ee66edd FC |
93 | '''Exports bam files from glTF ones.''' |
94 | _fname = '%s/%s' % (root, fname) | |
420ce99a FC |
95 | gltf_name = (_fname[:-5] + 'gltf').replace('/blend/', '/gltf/', 1) |
96 | bam_name = (_fname[:-5] + 'bam').replace('/blend/', '/bam/', 1) | |
8ee66edd FC |
97 | cmd_args = gltf_name, bam_name |
98 | # use dds files in place of png/jpg in gltf2bam | |
99 | copyfile(gltf_name, gltf_name + '.tmp') | |
100 | with open(gltf_name) as fgltf: | |
101 | lines = fgltf.readlines() | |
102 | deps = [] | |
103 | for line in lines: | |
104 | if ('.png' in line or '.jpg' in line) and '"uri"' in line: | |
105 | rln = line[line.index('"uri"') + 9:].rstrip(',\n"') | |
106 | tname = '%s/%s' % (root, rln) | |
420ce99a | 107 | deps += [tname.replace('/models/blend/', '/models/gltf/', 1)] |
8ee66edd FC |
108 | for dep in deps: |
109 | tgt = dep.replace('/gltf/', '/bam/', 1) | |
110 | tgt = tgt.replace('.png', '.dds').replace('.jpg', '.dds') | |
111 | makedirs(dirname(tgt), exist_ok=True) | |
112 | info('convert %s %s' % (dep, tgt)) | |
113 | system('convert %s %s' % (dep, tgt)) | |
e65a09cf FC |
114 | |
115 | def rpl(lin): | |
116 | lin = lin.replace('.png', '.dds') | |
117 | lin = lin.replace('.jpg', '.dds') | |
118 | lin = lin.replace('/png', '/dds') | |
119 | return lin.replace('/jpg', '/dds') | |
8ee66edd FC |
120 | with open(gltf_name, 'w') as fgltf: |
121 | fgltf.write(''.join([rpl(line) for line in lines])) | |
122 | makedirs(dirname(bam_name), exist_ok=True) | |
123 | if to_be_built(bam_name, deps): | |
218c8938 FC |
124 | system('gltf2bam %s %s' % cmd_args) |
125 | self._cache_files += [bam_name] + deps |