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