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