ya2 · news · projects · code · about

dds and bam
[pmachines.git] / lib / build / models.py
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])
54 pgltf = 'assets/models/gltf/'
55 gltf_name = _fname.replace('assets/models/blend/', pgltf)
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]
63 new_dir = root.replace('assets/models/blend/', pgltf)
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))
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)
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)
87 gltf_name = (_fname[:-5] + 'gltf').replace('/blend/', '/gltf/', 1)
88 bam_name = (_fname[:-5] + 'bam').replace('/blend/', '/bam/', 1)
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)
99 deps += [tname.replace('/models/blend/', '/models/gltf/', 1)]
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))
106 rpl = lambda lin: lin.replace('.png', '.dds').replace('.jpg', '.dds').replace('/png', '/dds').replace('/jpg', '/dds')
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