# Creation of Windows batch files to automate the compilation of # mental ray shaders for the book "Writing mental ray shaders" # http://www.writingshaders.com import sys, os, string, re def initial_comment(bits=32, shader=None): sys_name = '%d-bit systems using Visual C++ 2008 Express' % (bits) if shader == 'components': shader_desc = ' for shader components\nREM' elif shader: shader_desc = ' for shader "%s"\nREM' % (shader) else: shader_desc = '' result = """ REM Microsoft "Windows" batch file for the compilation of the shaders contained REM in the book "Writing mental ray Shaders: A perceptual introduction". REM Compilation is described in http://www.writingshaders.com/compilation.html. REM Also see the subsection "Dynamic Linking of Shaders" in section "Using and REM Writing Shaders" in the on-line mental ray documentation. REM Compilation commands%s for %s. """ % (shader_desc, sys_name) return result.strip() + '\n' # A list of the shader source and component files are used to iterate over all shaders: shader_inventory_file = 'SHADER_NAMES' component_inventory_file = 'COMPONENT_NAMES' # Filename conventions: extension = 'bat' all_shaders_filebase = 'all_shaders' components_filebase = 'components' variables_filebase = 'set_variables' # Compilation and linking flags: C_32 = '/c /O2 /MD /nologo /W3 -DWIN_NT' C_64 = C_32 + ' -D64' CPP_32 = '/TP /c /O2 /MD /nologo /W3 /EHsc -DWIN_NT' CPP_64 = CPP_32 + ' -D64' INCLUDE_32 = '/I"C:\Program Files\mental images\mental ray nt-x86-vc8\include"' INCLUDE_64 = '/I"C:\Program Files\mental images\mental ray nt-x64\include"' LINK = '/nologo /nodefaultlib:LIBC.LIB /OPT:NOREF /INCREMENTAL:NO /DLL' MT = '-nologo -manifest' # Defining the batch file variables: def variables_filename(bits=32): if bits == 64: suffix = '_64' else: suffix = '' return '%s%s.%s' % (variables_filebase, suffix, extension) def var_name(s): return 'WMRS_' + s.split('_')[0] + '_FLAGS' def write_set_variables_file(bits=32): vars = re.sub('NN', str(bits), 'C_NN CPP_NN INCLUDE_NN LINK MT') result = '' for var in vars.split(): result += 'set %s=%s\n' % (var_name(var), eval(var)) fp = open(variables_filename(bits), 'w') fp.write(result) fp.close() # The commands to compile source files: def var(s): return '%%%s%% ' % (var_name(s)) def component_obj_files(shader_name): # This breaks the generality of having COMPONENT_NAMES, unfortunately. result = 'miaux.obj' if shader_name == 'newblocks.cpp': result += ' matrix.obj mrpoly.obj' return result def single_shader_commands(shader_name, bits=32, link=True): is_cpp = shader_name.endswith('.cpp') shader_basename = shader_name.split('.')[0] result = '\ncl ' if bits == 32: if is_cpp: result += var('CPP_32') else: result += var('C_32') result += var('INCLUDE_32') else: if is_cpp: result += var('CPP_64') else: result += var('C_64') result += var('INCLUDE_64') result += shader_name if link: result += '\nlink %s/OUT:%s.dll %s.obj %s shader.lib\n' % \ (var('LINK'), shader_basename, shader_basename, component_obj_files(shader_name)) result += 'mt %s%s.dll.manifest -outputresource:%s.dll;2' % \ (var('MT'), shader_basename, shader_basename) return result + '\n' # Batch file for all shaders: def all_shader_batchfile(shader_names, component_names, bits=32): if bits == 32: filename = all_shaders_filebase + '.' + extension else: filename = all_shaders_filebase + '_64.' + extension print 'Making batch file %s' % (filename) fp = open(filename, 'w') fp.write(initial_comment(bits) + '\n') fp.write('call %s\n' % (variables_filename(bits))) for component in component_names: #fp.write('\nREM Shader component "%s"\n' % (component)) fp.write(single_shader_commands(component, bits=bits, link=False)) for shader in shader_names: #fp.write('\nREM Shader "%s"\n' % (shader)) fp.write(single_shader_commands(shader, bits=bits)) fp.close() # Batch file for individual shaders: def individual_shader_batchfiles(shader_names, bits=32): for shader in shader_names: filebase = shader.split('.')[0] if bits == 32: filename = filebase + '.' + extension else: filename = filebase + '_64.' + extension print 'Making batch file %s' % (filename) fp = open(filename, 'w') fp.write(initial_comment(bits, shader) + '\n') c_lang = shader.endswith('.c') cpp_lang = shader.endswith('.cpp') fp.write('call %s\n' % (variables_filename(bits))) fp.write(single_shader_commands(shader, bits=bits)) fp.close() # Batch file for component files (e.g., miaux.obj): def component_batchfile(component_names, bits=32): if bits == 32: filename = components_filebase + '.' + extension else: filename = components_filebase + '_64.' + extension print 'Making batch file %s' % (filename) fp = open(filename, 'w') fp.write(initial_comment(bits, 'components') + '\n') fp.write('call %s\n' % (variables_filename(bits))) for component in component_names: #fp.write('\nREM Shader component "%s"\n' % (component)) fp.write(single_shader_commands(component, bits=bits, link=False)) fp.close() # Check shader and component inventory files: def check_file(filename, description): if not os.path.exists(filename): print ''' This script expects %s to be found in a file called "%s" in the current directory. ''' % (description, filename) sys.exit(1) # Make batch files: check_file(shader_inventory_file, 'shader names') check_file(component_inventory_file, 'component names') shader_names = open(shader_inventory_file).read().split() component_names = open(component_inventory_file).read().split() write_set_variables_file() write_set_variables_file(bits=64) individual_shader_batchfiles(shader_names) individual_shader_batchfiles(shader_names, bits=64) component_batchfile(component_names) component_batchfile(component_names, bits=64) all_shader_batchfile(shader_names, component_names) all_shader_batchfile(shader_names, component_names, bits=64)