summaryrefslogtreecommitdiffstats
path: root/o3d/cg_to_glsl
diff options
context:
space:
mode:
authoramarinichev@chromium.org <amarinichev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 22:11:41 +0000
committeramarinichev@chromium.org <amarinichev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 22:11:41 +0000
commit9393d635e9e49f21631fca011d87ac7be1b19d23 (patch)
tree1e6b6afee6d598649a9ab3e101b3702b416b2f18 /o3d/cg_to_glsl
parent9038098882dc2e0c8963132de61df26ac4253811 (diff)
downloadchromium_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-xo3d/cg_to_glsl/convert.py172
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)