File: create_shadertext.py

package info (click to toggle)
pymol 2.5.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 42,288 kB
  • sloc: cpp: 476,472; python: 76,538; ansic: 29,510; javascript: 6,792; sh: 47; makefile: 24
file content (135 lines) | stat: -rw-r--r-- 4,473 bytes parent folder | download
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])))