forked from schrodinger/pymol-open-source
-
Notifications
You must be signed in to change notification settings - Fork 2
/
create_shadertext.py
135 lines (112 loc) · 4.37 KB
/
create_shadertext.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import io as cStringIO
import sys, os
import time
import re
import glob
from collections import defaultdict
from os.path import dirname
from subprocess import Popen, PIPE
from distutils import dir_util
def create_all(generated_dir, pymoldir="."):
'''
Generate various stuff
'''
create_shadertext(
os.path.join(pymoldir, "data", "shaders"),
generated_dir,
os.path.join(generated_dir, "ShaderText.h"),
os.path.join(generated_dir, "ShaderText.cpp"))
create_buildinfo(generated_dir, pymoldir)
class openw(object):
"""
File-like object for writing files. File is actually only
written if the content changed.
"""
def __init__(self, filename):
if os.path.exists(filename):
self.out = cStringIO.StringIO()
self.filename = filename
else:
dir_util.mkpath(os.path.dirname(filename))
self.out = open(filename, "w")
self.filename = None
def close(self):
if self.out.closed:
return
if self.filename:
with open(self.filename) as handle:
oldcontents = handle.read()
newcontents = self.out.getvalue()
if oldcontents != newcontents:
self.out = open(self.filename, "w")
self.out.write(newcontents)
self.out.close()
def __getattr__(self, name):
return getattr(self.out, name)
def __enter__(self):
return self
def __exit__(self, *a, **k):
self.close()
def __del__(self):
self.close()
def create_shadertext(shaderdir, shaderdir2, outputheader, outputfile):
outputheader = openw(outputheader)
outputfile = openw(outputfile)
include_deps = defaultdict(set)
ifdef_deps = defaultdict(set)
# get all *.gs *.vs *.fs *.shared from the two input directories
shaderfiles = set()
for sdir in [shaderdir, shaderdir2]:
for ext in ['gs', 'vs', 'fs', 'shared']:
shaderfiles.update(map(os.path.basename,
sorted(glob.glob(os.path.join(sdir, '*.' + ext)))))
varname = '_shader_cache_raw'
outputheader.write('extern const char * %s[];\n' % varname)
outputfile.write('const char * %s[] = {\n' % varname)
for filename in sorted(shaderfiles):
shaderfile = os.path.join(shaderdir, filename)
if not os.path.exists(shaderfile):
shaderfile = os.path.join(shaderdir2, filename)
with open(shaderfile, 'r') as handle:
contents = handle.read()
if True:
outputfile.write('"%s", ""\n' % (filename))
for line in contents.splitlines():
line = line.strip()
# skip blank lines and obvious comments
if not line or line.startswith('//') and not '*/' in line:
continue
# write line, quoted, escaped and with a line feed
outputfile.write("\"%s\\n\"\n" % line.replace('\\', '\\\\').replace('"', r'\"'))
# include and ifdef dependencies
if line.startswith('#include'):
include_deps[line.split()[1]].add(filename)
elif line.startswith('#ifdef') or line.startswith('#ifndef'):
ifdef_deps[line.split()[1]].add(filename)
outputfile.write(',\n')
outputfile.write('0};\n')
# include and ifdef dependencies
for varname, deps in [
('_include_deps', include_deps),
('_ifdef_deps', ifdef_deps)]:
outputheader.write('extern const char * %s[];\n' % varname)
outputfile.write('const char * %s[] = {\n' % varname)
for name, itemdeps in deps.items():
outputfile.write('"%s", "%s", 0,\n' % (name, '", "'.join(sorted(itemdeps))))
outputfile.write('0};\n')
outputheader.close()
outputfile.close()
def create_buildinfo(outputdir, pymoldir='.'):
try:
sha = Popen(['git', 'rev-parse', 'HEAD'], cwd=pymoldir,
stdout=PIPE).stdout.read().strip().decode()
except OSError:
sha = ''
with openw(os.path.join(outputdir, 'PyMOLBuildInfo.h')) as out:
print('''
#define _PyMOL_BUILD_DATE %d
#define _PYMOL_BUILD_GIT_SHA "%s"
''' % (time.time(), sha), file=out)
if __name__ == "__main__":
create_shadertext(*sys.argv[1:6])
create_buildinfo(dirname(sys.argv[4]), dirname(dirname(sys.argv[1])))