def gen_source(out_src, files): with open(out_src, 'w') as f: f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') f.write('#include "{}.h"\n'.format( os.path.splitext(os.path.basename(out_src))[0])) f.write('namespace Oryol {\n') for file in files: file_path = get_file_path(file, out_src) if os.path.isfile(file_path): with open(file_path, 'rb') as src_file: file_data = src_file.read() file_name = get_file_cname(file) file_size = os.path.getsize(file_path) f.write('unsigned char {}[{}] = {{\n'.format( file_name, file_size)) num = 0 for byte in file_data: f.write(hex(ord(byte)) + ', ') num += 1 if 0 == num % 16: f.write('\n') f.write('\n};\n') else: genutil.fmtError( "Input file not found: '{}'".format(file_path)) f.write('} // namespace Oryol\n')
def gen_source(out_src, files): with open(out_src, 'w') as f: f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') f.write('#include "{}.h"\n'.format( os.path.splitext(os.path.basename(out_src))[0])) items = {} for file in files: file_path = get_file_path(file, out_src) if os.path.isfile(file_path): with open(file_path, 'rb') as src_file: file_data = src_file.read() file_name = get_file_cname(file) file_size = os.path.getsize(file_path) items[file_name] = file_size f.write('unsigned char {}[{}] = {{\n'.format( file_name, file_size)) num = 0 for byte in file_data: f.write(hex(ord(byte)) + ', ') num += 1 if 0 == num % 16: f.write('\n') f.write('\n};\n') else: genutil.fmtError( "Input file not found: '{}'".format(file_path)) f.write('dump_item dump_items[DUMP_NUM_ITEMS] = {\n') for name, size in items.items(): f.write('{{ "{}", {}, {} }},\n'.format(name[5:], name, size)) f.write('};\n')
def generate(input, out_src, out_hdr, args): with open(input, 'r') as f: try: yml = yaml.load(f) except yaml.YAMLError as exc: # show a proper error if YAML parsing fails util.setErrorLocation(exc.problem_mark.name, exc.problem_mark.line - 1) util.fmtError('YAML error: {}'.format(exc.problem)) util.setErrorLocation(input, 1) src_root_path = os.path.dirname(input) + '/' dst_dir = args['deploy_dir'] + '/' if 'options' in yml: if 'src_dir' in yml['options']: src_root_path += yml['options']['src_dir'] + '/' if util.getEnv('target_platform') == 'ios' and 'ios' in yml['options']: if 'dst_dir' in yml['options']['ios']: dst_dir += yml['options']['ios']['dst_dir'] + '/' elif util.getEnv( 'target_platform') == 'osx' and 'macos' in yml['options']: if 'dst_dir' in yml['options']['macos']: dst_dir += yml['options']['macos']['dst_dir'] + '/' elif 'dst_dir' in yml['options']: dst_dir += yml['options']['dst_dir'] del yml['options'] if not os.path.exists(dst_dir): os.makedirs(dst_dir) if check_dirty(src_root_path, input, out_hdr, yml): copy_files(src_root_path, dst_dir, yml) gen_header(out_hdr, yml)
def __init__(self, propertyName, prop): self.propertyName = propertyName self.variables = list() self.isFlag = False self.isStruct = False self.isResource = False if isinstance(prop, dict): if not "_type_" in prop: for varName, var in prop.items(): self.variables.append(GetVariableFromEntry(varName, var)) self.isStruct = True else: var = GetVariableFromEntry(propertyName, prop) if var.type is None: self.isFlag = True self.variables.append(var) else: var = GetVariableFromEntry(propertyName, prop) if var.type is None: self.isFlag = True self.variables.append(GetVariableFromEntry(propertyName, prop)) # Check to see if any of the types within the struct are resource. for var in self.variables: if var.type == IDLTypes.GetTypeString("resource"): if self.isStruct: util.fmtError( "Structs containing resources not supported!") self.isResource = True
def compile(lines, base_path, type, c_name, args) : fxcPath = findFxc() if not fxcPath : util.fmtError("fxc.exe not found!\n") ext = { 'vs': '.vsh', 'fs': '.psh' } profile = { 'vs': 'vs_5_0', 'fs': 'ps_5_0' } hlsl_src_path = base_path + '.hlsl' out_path = base_path + '.hlsl.h' # /Gec is backward compatibility mode cmd = [fxcPath, '/T', profile[type], '/Fh', out_path, '/Vn', c_name, '/Gec'] if 'debug' in args and args['debug'] == 'true' : cmd.extend(['/Zi', '/Od']) else : cmd.append('/O3') cmd.append(hlsl_src_path) output = callFxc(cmd) parseOutput(output, lines)
def gen_source(out_src, files) : with open(out_src, 'w') as f: f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') f.write('#include "{}.h"\n'.format(os.path.splitext(os.path.basename(out_src))[0])) f.write('namespace YAKC {\n') for file in files : file_path = get_file_path(file, out_src) if os.path.isfile(file_path) : with open(file_path, 'rb') as src_file: file_data = src_file.read() file_name = get_file_cname(file) file_size = os.path.getsize(file_path) f.write('unsigned char {}[{}] = {{\n'.format(file_name, file_size)) num = 0 for byte in file_data : f.write(hex(ord(byte)) + ', ') num += 1 if 0 == num%16: f.write('\n') f.write('\n};\n') else : genutil.fmtError("Input file not found: '{}'".format(file_path)) f.write('} // namespace YAKC\n')
def onUse(self, args) : if not self.current or not self.current.getTag() in ['block', 'vs', 'fs'] : util.fmtError("@use must come after @block, @vs or @fs!") if len(args) < 1: util.fmtError("@use must have at least one arg!") for arg in args : self.current.dependencies.append(Reference(arg, self.fileName, self.lineNumber))
def validate(lines, type, slVersion, outPath, cName) : ''' Validate a vertex-/fragment-shader pair. ''' fxcPath = findFxc() if not fxcPath : util.fmtError("fxc.exe not found!\n") ext = { 'vs': '.vsh', 'fs': '.psh' } profile = { 'vs': 'vs_5_0', 'fs': 'ps_5_0' } rootPath = os.path.splitext(outPath)[0] hlsl_src_path = rootPath + '.{}{}'.format(profile[type], ext[type]) with open(hlsl_src_path, 'w') as f : writeFile(f, lines) cmd = [fxcPath, '/T', profile[type], '/O3', '/Fh', outPath, '/Vn', cName, hlsl_src_path] print(cmd); output = callFxc(cmd) parseOutput(output, lines)
def validate(lines, type, slVersion, outPath, cName, args) : ''' Validate a vertex-/fragment-shader pair. ''' fxcPath = findFxc() if not fxcPath : util.fmtError("fxc.exe not found!\n") ext = { 'vs': '.vsh', 'fs': '.psh' } profile = { 'vs': 'vs_5_0', 'fs': 'ps_5_0' } rootPath = os.path.splitext(outPath)[0] hlsl_src_path = rootPath + '.{}{}'.format(profile[type], ext[type]) with open(hlsl_src_path, 'w') as f : writeFile(f, lines) cmd = [fxcPath, '/T', profile[type], '/Fh', outPath, '/Vn', cName] if 'debug' in args and args['debug'] == 'true' : cmd.extend(['/Zi', '/Od']) else : cmd.append('/O3') cmd.append(hlsl_src_path) output = callFxc(cmd) parseOutput(output, lines)
def validate(lines, type, slVersion, outPath, cName) : ''' Validate a vertex-/fragment-shader pair. ''' fxcPath = findFxc() if not fxcPath : util.fmtError("fxc.exe not found!\n") ext = { 'vs': '.vsh', 'fs': '.psh' } profile = { 'vs': 'vs_5_0', 'fs': 'ps_5_0' } f = tempfile.NamedTemporaryFile(suffix=ext[type], delete=False) writeFile(f, lines) f.close() cmd = [fxcPath, '/T', profile[type], '/O3', '/Fh', outPath, '/Vn', cName, f.name] output = callFxc(cmd) os.unlink(f.name) parseOutput(output, lines)
def AccessModeToClassString(accessMode): access = accessMode.lower() if (access == "rw"): return "Attr::ReadWrite" elif (access == "r"): return "Attr::ReadOnly" else: util.fmtError('"{}" is not a valid access mode!'.format(access))
def onProgram(self, args) : if not self.current or self.current.getTag() != 'bundle' : util.fmtError("@program must come after @bundle!") if len(args) != 2: util.fmtError("@program must have 2 args (vs fs)") vs = args[0] fs = args[1] self.current.programs.append(Program(vs, fs, self.fileName, self.lineNumber))
def load(self) : with open(self.vox_file, 'rb') as f : magic = f.read(4) if magic != 'VOX ': util.fmtError('{} is not a VOX file!'.format(self.vox_file)) version = struct.unpack('<I', f.read(4))[0] print("VOX file '{}' version={}".format(self.vox_file, version)) self.load_chunk(f)
def load(self): with open(self.vox_file, 'rb') as f: magic = f.read(4) if magic != 'VOX ': util.fmtError('{} is not a VOX file!'.format(self.vox_file)) version = struct.unpack('<I', f.read(4))[0] print("VOX file '{}' version={}".format(self.vox_file, version)) self.load_chunk(f)
def __init__(self, T, name, defVal): if not isinstance(T, str) and T is not None: util.fmtError('_type_ value is not a string value!') self.type = T if not isinstance(name, str): util.fmtError('_name_ value is not a string value!') self.name = name self.defaultValue = defVal
def onEnd(self, args): if not self.current or not self.current.getTag() in [ 'block', 'vs', 'fs', 'bundle' ]: util.fmtError("@end must come after @block, @vs, @fs or @bundle!") if len(args) != 0: util.fmtError("@end must not have arguments") self.current = None
def gen_header(out_hdr, src_dir, files): with open(out_hdr, 'w', encoding='utf-8') as f: f.write('#pragma once\n') f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') items = {} for file in files: title = '' if isinstance(file, dict): for name, t in file.items(): file = name title = t print(name, t) break file_path = get_file_path(file, src_dir, out_hdr) if os.path.isfile(file_path): with open(file_path, 'rb') as src_file: file_data = src_file.read() file_name = get_file_cname(file) file_size = os.path.getsize(file_path) if title != '' and (file_data[0] == 48 or file_data[0] == 49): file_data, file_size = tap2cas(file_data, file_size) items[file_name] = [title, file_size] print(items[file_name], file_name) f.write('unsigned char {}[{}] = {{\n'.format( file_name, file_size)) num = 0 for byte in file_data: if sys.version_info[0] >= 3: f.write("0x%02x" % byte + ', ') else: f.write(hex(ord(byte)) + ', ') num += 1 if 0 == num % 16: f.write('\n') f.write('\n};\n') else: genutil.fmtError( "Input file not found: '{}'".format(file_path)) f.write('#define TAPE 1\n') f.write('#define BIN 0\n') f.write( 'typedef struct { const char* name; const uint8_t* ptr; int size; const int type; } dump_item;\n' ) f.write('#define DUMP_NUM_ITEMS ({})\n'.format(len(items))) f.write('dump_item dump_items[DUMP_NUM_ITEMS] = {\n') for name, value in items.items(): size = value[1] if value[0] != '': title = value[0] type = 'TAPE' else: title = name[5:] type = 'BIN' f.write('{{ u8"{}", {}, {}, {} }},\n'.format( title, name, size, type)) f.write('};\n')
def parseTags(self, line): # first check if the line contains a tag, the tag must be # alone on the line tagStartIndex = line.find('@') if tagStartIndex != -1: if tagStartIndex > 0: util.fmtError("only whitespace allowed in front of tag") if line.find(';') != -1: util.fmtError("no semicolons allowed in tag lines") tagAndArgs = line[tagStartIndex + 1:].split() tag = tagAndArgs[0] args = tagAndArgs[1:] if tag == 'block': self.onBlock(args) elif tag == 'vs': self.onVertexShader(args) elif tag == 'fs': self.onFragmentShader(args) elif tag == 'bundle': self.onBundle(args) elif tag == 'use': self.onUse(args) elif tag == 'in': self.onIn(args) elif tag == 'out': self.onOut(args) elif tag == 'uniform': self.onUniform(args) elif tag == 'highp': self.onPrecision(args) elif tag == 'program': self.onProgram(args) elif tag == 'end': self.onEnd(args) else: util.fmtError("unrecognized @ tag '{}'".format(tag)) return '' # handle any $ macros for macro in macroKeywords: startIndex = line.find(macro) if startIndex != -1: if self.current is not None: line = line.replace(macro, macroKeywords[macro]) if macroKeywords[macro] not in self.current.macros: self.current.macros.append(macroKeywords[macro]) else: util.fmtError( '$ tag must come after @block, @vs, @fs and before @end' ) # if there are still $ characters in the line, it must be an # unrecognized macro keyword (typo?) if '$' in line: util.fmtError('unrecognized $ keyword!') return line
def onProgram(self, args): if not self.current or self.current.getTag() != 'bundle': util.fmtError("@program must come after @bundle!") if len(args) != 2: util.fmtError("@program must have 2 args (vs fs)") vs = args[0] fs = args[1] self.current.programs.append( Program(vs, fs, self.fileName, self.lineNumber))
def onInclude(self, args): if len(args) != 1: util.fmtError("@include must have 1 arg (name of included block)") if not self.current or not self.current.getTag() in ['vs', 'fs']: util.fmtError("@include must come after @vs or @fs!") if self.current: l = Line(None, self.fileName, self.lineNumber) l.include = args[0] self.current.lines.append(l)
def parseTags(self, line) : # first check if the line contains a tag, the tag must be # alone on the line tagStartIndex = line.find('@') if tagStartIndex != -1 : if tagStartIndex > 0 : util.fmtError("only whitespace allowed in front of tag") if line.find(';') != -1 : util.fmtError("no semicolons allowed in tag lines") tagAndArgs = line[tagStartIndex+1 :].split() tag = tagAndArgs[0] args = tagAndArgs[1:] if tag == 'block': self.onBlock(args) elif tag == 'vs': self.onVertexShader(args) elif tag == 'fs': self.onFragmentShader(args) elif tag == 'bundle': self.onBundle(args) elif tag == 'use': self.onUse(args) elif tag == 'in': self.onIn(args) elif tag == 'out': self.onOut(args) elif tag == 'uniform': self.onUniform(args) elif tag == 'highp' : self.onPrecision(args) elif tag == 'program': self.onProgram(args) elif tag == 'end': self.onEnd(args) else : util.fmtError("unrecognized @ tag '{}'".format(tag)) return '' # handle any $ macros for macro in macroKeywords : startIndex = line.find(macro) if startIndex != -1 : if self.current is not None: line = line.replace(macro, macroKeywords[macro]) if macroKeywords[macro] not in self.current.macros : self.current.macros.append(macroKeywords[macro]) else : util.fmtError('$ tag must come after @block, @vs, @fs and before @end') # if there are still $ characters in the line, it must be an # unrecognized macro keyword (typo?) if '$' in line : util.fmtError('unrecognized $ keyword!') return line
def onUse(self, args): if not self.current or not self.current.getTag() in [ 'block', 'vs', 'fs' ]: util.fmtError("@use must come after @block, @vs or @fs!") if len(args) < 1: util.fmtError("@use must have at least one arg!") for arg in args: self.current.dependencies.append( Reference(arg, self.fileName, self.lineNumber))
def WriteMessageDeclarations(f, document): for messageName, message in document["messages"].items(): if not "fourcc" in message: util.fmtError( 'Message FourCC is required. Message "{}" does not have a fourcc!' .format(messageName)) fourcc = message["fourcc"] templateArgs = "" messageParams = "" sendArgs = "" i = 1 numArgs = len(document["messages"][messageName]["args"]) for argName, T in document["messages"][messageName]["args"].items(): typeString = IDLTypes.GetArgumentType(T) templateArgs += typeString messageParams += "{} {}".format(typeString, argName) sendArgs += argName if i < numArgs: templateArgs += ", " messageParams += ", " sendArgs += ", " i += 1 f.InsertNebulaDivider() f.WriteLine( """class {MSG} : public Game::Message<{MSG}, {TemplateArguments}> {{ public: {MSG}() = delete; ~{MSG}() = delete; constexpr static const char* GetName() {{ return \"{MSG}\"; }}; constexpr static const uint GetFourCC() {{ return \'{FOURCC}\'; }}; static void Send({MessageParameters}) {{ auto instance = Instance(); SizeT size = instance->callbacks.Size(); for (SizeT i = 0; i < size; ++i) instance->callbacks.Get<1>(i)({SendArguments}); }} static void Defer(MessageQueueId qid, {MessageParameters}) {{ auto instance = Instance(); SizeT index = Ids::Index(qid.id); auto i = instance->messageQueues[index].Alloc(); instance->messageQueues[index].Set(i, {SendArguments}); }} }}; """.format( MSG=messageName, TemplateArguments=templateArgs, FOURCC=fourcc, MessageParameters=messageParams, SendArguments=sendArgs, ))
def run(cmd): child = subprocess.Popen(cmd, stderr=subprocess.PIPE) out = '' while True: out += bytes.decode(child.stderr.read()) if child.poll() != None: break for line in out.splitlines(): util.fmtError(line, False) if child.returncode != 0: exit(child.returncode)
def run(cmd): child = subprocess.Popen(cmd, stderr=subprocess.PIPE) out = '' while True : out += bytes.decode(child.stderr.read()) if child.poll() != None : break for line in out.splitlines(): util.fmtError(line, False) if child.returncode != 0: exit(child.returncode)
def parseSource(self, fileName): f = open(fileName, 'r') self.fileName = fileName self.lineNumber = 0 for line in f: util.setErrorLocation(self.fileName, self.lineNumber) self.parseLine(line) self.lineNumber += 1 f.close() if self.current is not None: util.fmtError('missing @end at end of file')
def parseOutput(output, lines) : ''' Parse error output lines from FXC, map them to the original source code location and output an error message compatible with Xcode or VStudio ''' hasError = False hasWarning = False outLines = output.splitlines() for outLine in outLines : # extract generated shader source column, line and message # format is 'filename(line,startcol-endcol): msg lineStartIndex = outLine.find('(', 0) + 1 if lineStartIndex == 0 : continue lineEndIndex = outLine.find(',', lineStartIndex) if lineEndIndex == -1 : continue colStartIndex = lineEndIndex + 1 colEndIndex = outLine.find('-', colStartIndex) if colEndIndex == -1 : colEndIndex = outLine.find(')', colStartIndex) if colEndIndex == -1 : continue msgStartIndex = outLine.find(':', colStartIndex+1) if msgStartIndex == -1 : continue colNr = int(outLine[colStartIndex:colEndIndex]) lineNr = int(outLine[lineStartIndex:lineEndIndex]) msg = outLine[msgStartIndex:] # map to original location lineIndex = lineNr - 1 if lineIndex >= len(lines) : lineIndex = len(lines) - 1 srcPath = lines[lineIndex].path srcLineNr = lines[lineIndex].lineNumber # and output... util.setErrorLocation(srcPath, srcLineNr) if 'error' in outLine : hasError = True util.fmtError(msg, False) elif 'warning' in outLine : hasWarning = True util.fmtWarning(msg) if hasError : for line in lines : print(line.content) sys.exit(10)
def parseOutput(output, lines): ''' Parse error output lines from FXC, map them to the original source code location and output an error message compatible with Xcode or VStudio ''' hasError = False hasWarning = False outLines = output.splitlines() for outLine in outLines: # extract generated shader source column, line and message # format is 'filename(line,startcol-endcol): msg lineStartIndex = outLine.find('(', 0) + 1 if lineStartIndex == 0: continue lineEndIndex = outLine.find(',', lineStartIndex) if lineEndIndex == -1: continue colStartIndex = lineEndIndex + 1 colEndIndex = outLine.find('-', colStartIndex) if colEndIndex == -1: colEndIndex = outLine.find(')', colStartIndex) if colEndIndex == -1: continue msgStartIndex = outLine.find(':', colStartIndex + 1) if msgStartIndex == -1: continue colNr = int(outLine[colStartIndex:colEndIndex]) lineNr = int(outLine[lineStartIndex:lineEndIndex]) msg = outLine[msgStartIndex:] # map to original location lineIndex = lineNr - 1 if lineIndex >= len(lines): lineIndex = len(lines) - 1 srcPath = lines[lineIndex].path srcLineNr = lines[lineIndex].lineNumber # and output... util.setErrorLocation(srcPath, srcLineNr) if 'error' in outLine: hasError = True util.fmtError(msg, False) elif 'warning' in outLine: hasWarning = True util.fmtWarning(msg) if hasError: for line in lines: print(line.content) sys.exit(10)
def resolveDeps(self, shd, dep) : ''' Recursively resolve dependencies for a shader. ''' # just add new dependencies at the end of resolvedDeps, # and remove dups in a second pass after recursion if not dep.name in self.blocks : util.setErrorLocation(dep.path, dep.lineNumber) util.fmtError("unknown block dependency '{}'".format(dep.name)) shd.resolvedDeps.append(dep.name) for depdep in self.blocks[dep.name].dependencies : self.resolveDeps(shd, depdep)
def onProgram(self, args): if len(args) != 3: util.fmtError("@program must have 3 args (name vs fs)") if self.current is not None: util.fmtError( "cannot nest @program (missing @end tag in '{}'?)".format( self.current.name)) name = args[0] vs = args[1] fs = args[2] prog = Program(name, vs, fs, self.fileName, self.lineNumber) self.shaderLib.programs[name] = prog
def resolveDeps(self, shd, dep): ''' Recursively resolve dependencies for a shader. ''' # just add new dependencies at the end of resolvedDeps, # and remove dups in a second pass after recursion if not dep.name in self.blocks: util.setErrorLocation(dep.path, dep.lineNumber) util.fmtError("unknown block dependency '{}'".format(dep.name)) shd.resolvedDeps.append(dep.name) for depdep in self.blocks[dep.name].dependencies: self.resolveDeps(shd, depdep)
def copy_files(src_dir, dst_dir, yml): for filename in yml['files']: src = src_dir + filename dst = dst_dir + filename print("## cp '{}' => '{}'".format(filename, dst)) if not os.path.exists(os.path.dirname(dst)): os.makedirs(os.path.dirname(dst)) try: shutil.copyfile(src, dst) except IOError as err: # show a proper error if file copying fails util.fmtError("Failed to copy file '{}' with '{}'".format( err.filename, err.strerror))
def checkAddUniform(self, uniform, list): ''' Check if uniform already exists in list, if yes check if type and binding matches, if not write error. If uniform doesn't exist yet in list, add it. ''' listUniform = findByName(uniform.name, list) if listUniform is not None: # redundant uniform, check if type and binding name match if listUniform.type != uniform.type: util.setErrorLocation(uniform.filePath, uniform.lineNumber) util.fmtError( "uniform type mismatch '{}' vs '{}'".format( uniform.type, listUniform.type), False) util.setErrorLocation(listUniform.filePath, listUniform.lineNumber) util.fmtError("uniform type mismatch '{}' vs '{}'".format( listUniform.type, uniform.type)) if listUniform.bind != uniform.bind: util.setErrorLocation(uniform.filePath, uniform.lineNumber) util.fmtError( "uniform bind name mismatch '{}' vs '{}'".format( uniform.bind, listUniform.bind), False) util.setErrorLocation(listUniform.filePath, listUniform.lineNumber) util.fmtError("uniform bind name mismatch '{}' vs '{}'".format( listUniform.bind, uniform.bind)) else: # new uniform from block, add to list list.append(uniform)
def WriteAttributeAccessDeclarations(self): if self.hasAttributes: self.f.WriteLine("/// Attribute access methods") for attributeName in self.component["attributes"]: if not attributeName in self.document["attributes"]: util.fmtError(AttributeNotFoundError.format(attributeName)) returnType = IDLTypes.GetTypeString( self.document["attributes"][attributeName]["type"]) attributeName = Capitalize(attributeName) self.f.WriteLine( "{retval}& {attributeName}(Game::InstanceId instance);". format(retval=returnType, attributeName=attributeName))
def parseSource(self, fileName) : ''' Parse a single file and populate shader lib ''' f = open(fileName, 'r') self.fileName = fileName self.lineNumber = 0 for line in f : util.setErrorLocation(self.fileName, self.lineNumber) self.parseLine(line) self.lineNumber += 1 f.close() # all blocks must be closed if self.current is not None : util.fmtError('missing @end at end of file')
def resolveBundleUniforms(self, bundle) : ''' Gathers all uniforms from all shaders in the bundle. ''' for program in bundle.programs : if program.vs not in self.vertexShaders : util.setErrorLocation(program.filePath, program.lineNumber) util.fmtError("unknown vertex shader '{}'".format(program.vs)) for uniform in self.vertexShaders[program.vs].uniforms : self.checkAddUniform(uniform, bundle.uniforms) if program.fs not in self.fragmentShaders : util.setErrorLocation(program.filePath, program.lineNumber) util.fmtError("unknown fragment shader '{}'".format(program.fs)) for uniform in self.fragmentShaders[program.fs].uniforms : self.checkAddUniform(uniform, bundle.uniforms)
def generateShaderSources(self): for shd in self.shaders: lines = [] for l in shd.lines: # @include statement? if l.include: if l.include not in self.blocks: util.setErrorLocation(incl.path, incl.lineNumber) util.fmtError( "included block '{}' doesn't exist".format( incl.name)) for lb in self.blocks[l.include].lines: lines.append(lb) else: lines.append(l) shd.generatedSource = lines
def parseSource(self, fileName): ''' Parse a single file and populate shader lib ''' f = open(fileName, 'r') self.fileName = fileName self.lineNumber = 0 for line in f: util.setErrorLocation(self.fileName, self.lineNumber) self.parseLine(line) self.lineNumber += 1 f.close() # all blocks must be closed if self.current is not None: util.fmtError('missing @end at end of file')
def GetTypeCamelNotation(attributeName, attribute, document): if not "type" in attribute: util.fmtError( 'Attribute type is required. Attribute "{}" does not name a type!'. format(attributeName)) typeString = IDLTypes.ConvertToCamelNotation(attribute["type"]) if not typeString: # Figure out what type it actually is. if attribute["type"] in document["enums"]: typeString = IDLTypes.ConvertToCamelNotation( "uint") # type for enums is uint else: util.fmtError('"{}" is not a valid type!'.format( attribute["type"])) return typeString
def gen_header(out_hdr, files) : with open(out_hdr, 'w') as f: f.write('#pragma once\n') f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') f.write('namespace YAKC {\n') for file in files : file_path = get_file_path(file, out_hdr) if os.path.isfile(file_path) : file_name = get_file_cname(file) file_size = os.path.getsize(file_path) f.write('extern unsigned char {}[{}];\n'.format(file_name, file_size)) else : genutil.fmtError("Input file not found: '{}'".format(file_path)) f.write('} // namespace YAKC\n')
def AsTypeDefString(self): if self.isFlag: return "" numVars = len(self.variables) if numVars == 0: util.fmtError( "PropertyDefinition does not contain a single variable!") elif numVars == 1 and not self.isStruct: return 'typedef {} {};\n'.format(self.variables[0].type, self.variables[0].name) else: varDefs = "" retVal = 'struct {}\n{{\n'.format(self.propertyName) for v in self.variables: retVal += ' {}\n'.format(v.AsString()) retVal += "};\n" return retVal
def generate(input, out_src, out_hdr, args): with open(input, 'r') as f: try: yml = yaml.load(f) except yaml.YAMLError as exc: # show a proper error if YAML parsing fails util.setErrorLocation(exc.problem_mark.name, exc.problem_mark.line-1) util.fmtError('YAML error: {}'.format(exc.problem)) src_root_path = os.path.dirname(input) + '/' if 'root' in yml: src_root_path += yml['root'] + '/' deploy_dir = args['deploy_dir'] + '/' if not os.path.exists(deploy_dir): os.makedirs(deploy_dir) if check_dirty(src_root_path, input, out_hdr, yml): copy_files(src_root_path, deploy_dir, yml) gen_header(out_hdr, yml)
def stripComments(self, line) : ''' Remove comments from a single line, can carry over to next or from previous line. ''' done = False while not done : # if currently in comment, look for end-of-comment if self.inComment : endIndex = line.find('*/') if endIndex == -1 : # entire line is comment if '/*' in line or '//' in line : util.fmtError('comment in comment!') else : return '' else : comment = line[:endIndex+2] if '/*' in comment or '//' in comment : util.fmtError('comment in comment!') else : line = line[endIndex+2:] self.inComment = False # clip off winged comment (if exists) wingedIndex = line.find('//') if wingedIndex != -1 : line = line[:wingedIndex] # look for start of comment startIndex = line.find('/*') if startIndex != -1 : # ...and for the matching end... endIndex = line.find('*/', startIndex) if endIndex != -1 : line = line[:startIndex] + line[endIndex+2:] else : # comment carries over to next line self.inComment = True line = line[:startIndex] done = True else : # no comment until end of line, done done = True; line = line.strip(' \t\n\r') return line
def stripComments(self, line): ''' Remove comments from a single line, can carry over to next or from previous line. ''' done = False while not done: # if currently in comment, look for end-of-comment if self.inComment: endIndex = line.find('*/') if endIndex == -1: # entire line is comment if '/*' in line or '//' in line: util.fmtError('comment in comment!') else: return '' else: comment = line[:endIndex + 2] if '/*' in comment or '//' in comment: util.fmtError('comment in comment!') else: line = line[endIndex + 2:] self.inComment = False # clip off winged comment (if exists) wingedIndex = line.find('//') if wingedIndex != -1: line = line[:wingedIndex] # look for start of comment startIndex = line.find('/*') if startIndex != -1: # ...and for the matching end... endIndex = line.find('*/', startIndex) if endIndex != -1: line = line[:startIndex] + line[endIndex + 2:] else: # comment carries over to next line self.inComment = True line = line[:startIndex] done = True else: # no comment until end of line, done done = True line = line.strip(' \t\n\r') return line
def resolveBundleUniforms(self, bundle): ''' Gathers all uniforms from all shaders in the bundle. ''' for program in bundle.programs: if program.vs not in self.vertexShaders: util.setErrorLocation(program.filePath, program.lineNumber) util.fmtError("unknown vertex shader '{}'".format(program.vs)) for uniform in self.vertexShaders[program.vs].uniforms: self.checkAddUniform(uniform, bundle.uniforms) if program.fs not in self.fragmentShaders: util.setErrorLocation(program.filePath, program.lineNumber) util.fmtError("unknown fragment shader '{}'".format( program.fs)) for uniform in self.fragmentShaders[program.fs].uniforms: self.checkAddUniform(uniform, bundle.uniforms)
def gen_header(out_hdr, src_dir, files, prefix, list_items): with open(out_hdr, 'w') as f: f.write('#pragma once\n') f.write('// #version:{}#\n'.format(Version)) f.write('// machine generated, do not edit!\n') items = {} for file in files: file_path = get_file_path(file, src_dir, out_hdr) print("## embed '{}'".format(file_path)) if os.path.isfile(file_path): with open(file_path, 'rb') as src_file: file_data = src_file.read() file_cname = get_file_cname(file, prefix) file_size = os.path.getsize(file_path) items[file_cname] = [file, file_size] f.write('unsigned char {}[{}] = {{\n'.format( file_cname, file_size)) num = 0 for byte in file_data: if sys.version_info[0] >= 3: f.write(hex(ord(chr(byte))) + ', ') else: f.write(hex(ord(byte)) + ', ') num += 1 if 0 == num % 16: f.write('\n') f.write('\n};\n') else: genutil.fmtError( "Input file not found: '{}'".format(file_path)) if list_items: f.write( 'typedef struct {{ const char* name; const uint8_t* ptr; int size; }} {}item_t;\n' .format(prefix)) f.write('#define {}NUM_ITEMS ({})\n'.format( prefix.upper(), len(items))) f.write('{}item_t {}items[{}NUM_ITEMS] = {{\n'.format( prefix, prefix, prefix.upper())) for name, item in sorted(items.items()): size = item[1] text = name[(len(prefix)):] if 'full' == list_items: text = item[0] f.write('{{ "{}", {}, {} }},\n'.format(text, name, size)) f.write('};\n')
def parseOutput(output, lines) : ''' Parse error output lines from the GLSL reference compiler, map them to the original source code location and output an error message compatible with Xcode or VStudio ''' hasError = False outLines = output.splitlines() for outLine in outLines : if outLine.startswith('ERROR: ') : hasError = True # extract generated shader source column, line and message colStartIndex = 7 colEndIndex = outLine.find(':', colStartIndex) if colEndIndex == -1 : continue lineStartIndex = colEndIndex + 1 lineEndIndex = outLine.find(':', lineStartIndex) if lineEndIndex == -1 : continue msgStartIndex = lineEndIndex + 1 colNr = int(outLine[colStartIndex:colEndIndex]) lineNr = int(outLine[lineStartIndex:lineEndIndex]) msg = outLine[msgStartIndex:] # map to original location lineIndex = lineNr - 1 if lineIndex >= len(lines) : lineIndex = len(lines) - 1 srcPath = lines[lineIndex].path srcLineNr = lines[lineIndex].lineNumber # and output... util.setErrorLocation(srcPath, srcLineNr) util.fmtError(msg, False) if hasError : for line in lines : print "{}\n".format(line.content) util.fmtError("Aborting.")
def onPrecision(self, args) : if not self.current or not self.current.getTag() in ['vs', 'fs'] : util.fmtError("@highp must come after @vs or @fs!") if len(args) != 1: util.fmtError("@highp must have 1 arg (type)") type = args[0] if checkListDup(type, self.current.highPrecision) : util.fmtError("@highp type '{}' already defined in '{}'!".format(type, self.current.name)) self.current.highPrecision.append(type)
def parseOutput(output, lines) : hasError = False hasWarnings = False outLines = output.splitlines() for outLine in outLines : if 'error:' in outLine or 'warning:' in outLine or 'note:' in outLine: tokens = outLine.split(':') metalSrcPath = tokens[0] lineNr = int(tokens[1]) colNr = int(tokens[2]) msgType = tokens[3] msg = tokens[4] if msgType == ' error': hasError = True if msgType == ' warning': hasWarning = True # map to original location lineIndex = lineNr - 1 if lineIndex >= len(lines) : lineIndex = len(lines) - 1 srcPath = lines[lineIndex].path srcLineNr = lines[lineIndex].lineNumber # and output... util.setErrorLocation(srcPath, srcLineNr) util.fmtError(msg, False) if hasError : for outLine in outLines : print(outLine) for line in lines : print(line.content) sys.exit(10)
def onOut(self, args) : if not self.current or not self.current.getTag() in ['vs'] : util.fmtError("@out must come after @vs!") if len(args) != 2: util.fmtError("@out must have 2 args (type name)") type = args[0] name = args[1] if checkListDup(name, self.current.outputs) : util.fmtError("@out '{}' already defined in '{}'!".format(name, self.current.name)) self.current.outputs.append(Attr(type, name, self.fileName, self.lineNumber))
def onBundle(self, args) : if len(args) != 1: util.fmtError("@bundle must have 1 arg (name)") if self.current is not None : util.fmtError("cannot nest @bundle (missing @end tag in '{}'?)".format(self.current.name)) name = args[0] if name in self.shaderLib.bundles : util.fmtError("@bundle '{}' already defined!".format(name)) bundle = Bundle(name) self.shaderLib.bundles[name] = bundle self.current = bundle
def onBlock(self, args) : if len(args) != 1 : util.fmtError("@block must have 1 arg (name)") if self.current is not None : util.fmtError("cannot nest @block (missing @end in '{}'?)".format(self.current.name)) name = args[0] if name in self.shaderLib.blocks : util.fmtError("@block '{}' already defined".format(name)) block = Block(name) self.shaderLib.blocks[name] = block self.current = block
def onVertexShader(self, args) : if len(args) != 1: util.fmtError("@vs must have 1 arg (name)") if self.current is not None : util.fmtError("cannot nest @vs (missing @end in '{}'?)".format(self.current.name)) name = args[0] if name in self.shaderLib.vertexShaders : util.fmtError("@vs '{}' already defined".format(name)) vs = VertexShader(name) self.shaderLib.vertexShaders[name] = vs self.current = vs
def onUniform(self, args) : if not self.current or not self.current.getTag() in ['block', 'vs', 'fs'] : util.fmtError("@uniform must come after @block, @vs or @fs tag!") if len(args) != 3: util.fmtError("@uniform must have 3 args (type name binding)") type = args[0] name = args[1] bind = args[2] if checkListDup(name, self.current.uniforms) : util.fmtError("@uniform '{}' already defined in '{}'!".format(name, self.current.name)) self.current.uniforms.append(Uniform(type, name, bind, self.fileName, self.lineNumber))
def onFragmentShader(self, args) : if len(args) != 1: util.fmtError("@fs must have 1 arg (name)") if self.current is not None : util.fmtError("cannot nest @fs (missing @end in '{}'?)".format(self.current.name)) name = args[0] if name in self.shaderLib.fragmentShaders : util.fmtError("@fs '{}' already defined!".format(name)) fs = FragmentShader(name) self.shaderLib.fragmentShaders[name] = fs self.current = fs
def checkAddUniform(self, uniform, list) : ''' Check if uniform already exists in list, if yes check if type and binding matches, if not write error. If uniform doesn't exist yet in list, add it. ''' listUniform = findByName(uniform.name, list) if listUniform is not None: # redundant uniform, check if type and binding name match if listUniform.type != uniform.type : util.setErrorLocation(uniform.filePath, uniform.lineNumber) util.fmtError("uniform type mismatch '{}' vs '{}'".format(uniform.type, listUniform.type), False) util.setErrorLocation(listUniform.filePath, listUniform.lineNumber) util.fmtError("uniform type mismatch '{}' vs '{}'".format(listUniform.type, uniform.type)) if listUniform.bind != uniform.bind : util.setErrorLocation(uniform.filePath, uniform.lineNumber) util.fmtError("uniform bind name mismatch '{}' vs '{}'".format(uniform.bind, listUniform.bind), False) util.setErrorLocation(listUniform.filePath, listUniform.lineNumber) util.fmtError("uniform bind name mismatch '{}' vs '{}'".format(listUniform.bind, uniform.bind)) else : # new uniform from block, add to list list.append(uniform)
def onEnd(self, args) : if not self.current or not self.current.getTag() in ['block', 'vs', 'fs', 'bundle'] : util.fmtError("@end must come after @block, @vs, @fs or @bundle!") if len(args) != 0: util.fmtError("@end must not have arguments") self.current = None