diff options
author | amarinichev@chromium.org <amarinichev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 22:11:41 +0000 |
---|---|---|
committer | amarinichev@chromium.org <amarinichev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 22:11:41 +0000 |
commit | 9393d635e9e49f21631fca011d87ac7be1b19d23 (patch) | |
tree | 1e6b6afee6d598649a9ab3e101b3702b416b2f18 /o3d/cg_to_glsl | |
parent | 9038098882dc2e0c8963132de61df26ac4253811 (diff) | |
download | chromium_src-9393d635e9e49f21631fca011d87ac7be1b19d23.zip chromium_src-9393d635e9e49f21631fca011d87ac7be1b19d23.tar.gz chromium_src-9393d635e9e49f21631fca011d87ac7be1b19d23.tar.bz2 |
A simple script to convert o3d cg shaders to glsl.
Review URL: http://codereview.chromium.org/1595017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44831 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/cg_to_glsl')
-rwxr-xr-x | o3d/cg_to_glsl/convert.py | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/o3d/cg_to_glsl/convert.py b/o3d/cg_to_glsl/convert.py new file mode 100755 index 0000000..8eb86ec --- /dev/null +++ b/o3d/cg_to_glsl/convert.py @@ -0,0 +1,172 @@ +#!/usr/bin/python +import optparse +import os +import re +import subprocess +import sys + +# This script takes an o3d cg shader from standard input and does the following: +# +# * it extracts entry points to vertex and fragment shaders as specified by +# VertexShaderEntryPoint and PixelShaderEntryPoint instructions; +# +# * renames NORMAL, TANGENT{,1} and BINORMAL{,1} attributes to ATTR8-12; +# +# * runs cgc with glslv and glslf profiles with those entry points; +# +# * renames attributes and uniforms back to their orignal names; +# +# * changes 'uniform vecN var[N]' to 'uniform matN var'; +# +# * renames gl_Vertex and gl_MultiTexCoordN to position and texcoordsN +# respectively and adds attribute declarations; +# +# * prints the results to standard output, separating them with SplitMarker +# instruction and keeping the MatrixLoadOrder instruction as is. + + +CGC = '/usr/bin/cgc' + +# cgc complains about TANGENT1 and BINORMAL1 semantics, so we hack it by +# replacing standard semantics with ATTR8-ATTR12 and then renaming them back to +# their original names. +ATTRIBUTES_TO_SEMANTICS = dict( + attr8 = 'normal', + attr9 = 'tangent', + attr10 = 'binormal', + attr11 = 'tangent1', + attr12 = 'binormal1') + + +def get_input_mapping(header): + ret = dict() + for l in header.splitlines(): + if not l.startswith('//var'): + continue + old_name_and_type, semantic, new_name, _, _ = l.split(' : ') + if '[' in new_name: + new_name = new_name[:new_name.index('[')] + if new_name.startswith('$'): + new_name = new_name[1:] + ret[new_name] = (semantic.lower() if semantic + else old_name_and_type.split(' ')[2]) + return ret + + +def fix_glsl_body(body, input_mapping): + # Change uniform names back to original. + for match in re.findall(r'(?m)^uniform (?:\w+) (\w+)', body): + body = re.sub(r'\b%s\b' % match, input_mapping[match], body) + + # Change attribute names back to original. + for match in re.findall(r'(?m)^attribute (?:\w+) (\w+)', body): + attr_name = input_mapping[match] + assert attr_name.startswith('$vin.') + orig_name = ATTRIBUTES_TO_SEMANTICS[attr_name[len('$vin.'):]] + body = re.sub(r'\b%s\b' % match, orig_name, body) + + # Change vecN blah[N]; to matN blah; + body = re.sub(r'(?m)^uniform vec(\d) (\w+)\[\1\];', r'uniform mat\1 \2;', + body) + + attributes = [] + if 'gl_Vertex' in body: + # Change gl_Vertex to position and add attribute declaration. + body = re.sub(r'\bgl_Vertex\b', 'position', body) + attributes.append('attribute vec4 position;') + + for n in xrange(8): + if 'gl_MultiTexCoord%d' % n in body: + # Change gl_MultiTexCoordN (0<=N<=7) to texcoordsN and add attribute + # declaration. + body = re.sub(r'\bgl_MultiTexCoord%d\b' % n, 'texcoords%d' % n, body) + attributes.append('attribute vec4 texcoords%d;' % n) + + # ATTRIBUTES_TO_SEMANTICS should have taken care of normals. + assert 'gl_Normal' not in body + + return '\n'.join(attributes) + '\n\n' + body + + +def fix_glsl(glsl_shader): + header, body = re.split(r'\n\n', glsl_shader, 1) + assert all(l.startswith('//') for l in header.splitlines()) + input_mapping = get_input_mapping(header) + return header + '\n\n' + fix_glsl_body(body, input_mapping) + + +def cg_rename_attributes(cg_shader): + for new, old in ATTRIBUTES_TO_SEMANTICS.iteritems(): + cg_shader = re.sub(r'\b%s\b' % old.upper(), new.upper(), cg_shader) + return cg_shader + + +def cg_to_glsl(cg_shader): + cg_shader = cg_rename_attributes(cg_shader) + + vertex_entry = re.search(r'#o3d\s+VertexShaderEntryPoint\s+(\w+)', + cg_shader).group(1) + p = subprocess.Popen(CGC+' -profile glslv -entry %s' % vertex_entry, + shell=True, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + glsl_vertex, err_v = p.communicate(cg_shader) + + fragment_entry = re.search(r'#o3d\s+PixelShaderEntryPoint\s+(\w+)', + cg_shader).group(1) + p = subprocess.Popen(CGC+' -profile glslf -entry %s' % fragment_entry, + shell=True, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + glsl_fragment, err_f = p.communicate(cg_shader) + + log = ( + '// glslv profile log:\n' + + '\n'.join('// ' + l for l in err_v.splitlines()) + '\n\n' + '// glslf profile log:\n' + + '\n'.join('// ' + l for l in err_f.splitlines())) + '\n' + + return glsl_vertex, glsl_fragment, log + + +def get_matrixloadorder(cg_shader): + return re.search(r'(?m)^.*#o3d\s+MatrixLoadOrder\b.*$', cg_shader).group(0) + + +def check_cg(): + if not os.path.exists(CGC): + print >>sys.stderr, CGC+' is not found, use --cgc option to specify its' + print >>sys.stderr, 'location. You may need to install nvidia cg toolkit.' + print >>sys.stderr, 'In Ubuntu distribution it can be done by running:' + print >>sys.stderr, ' "apt-get install nvidia-cg-toolkit"' + sys.exit(1) + + +def main(cg_shader): + matrixloadorder = get_matrixloadorder(cg_shader) + glsl_vertex, glsl_fragment, log = cg_to_glsl(cg_shader) + + print log + print fix_glsl(glsl_vertex) + print + print '// #o3d SplitMarker' + print get_matrixloadorder(cg_shader).strip() + print + print fix_glsl(glsl_fragment) + + +if __name__ == '__main__': + cmdline_parser = optparse.OptionParser() + cmdline_parser.add_option('--cgc', dest='CGC', default='/usr/bin/cgc', + help='path to cgc [default: %default]') + options, args = cmdline_parser.parse_args() + CGC = options.CGC + check_cg() + + try: + input = sys.stdin.read() + except KeyboardInterrupt: + input = None + + if not input: + cmdline_parser.print_help() + else: + main(input) |