Exemplo n.º 1
0
 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))
Exemplo n.º 2
0
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
    '''
    outLines = output.splitlines()
    for outLine in outLines :
        if outLine.startswith('ERROR: ') :
            # 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)
Exemplo n.º 3
0
 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))
Exemplo n.º 4
0
 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))
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
 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))
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
 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)
Exemplo n.º 10
0
 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)
Exemplo n.º 11
0
 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)
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
    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)
Exemplo n.º 14
0
    def parseSource(self, fileName) :
        '''
        Parse a single file and populate shader lib
        '''
        print '=> parsing {}'.format(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()

        # all blocks must be closed
        if self.current is not None :
            util.fmtError('missing @end at end of file')
Exemplo n.º 15
0
    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
Exemplo n.º 16
0
    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
Exemplo n.º 17
0
    def parseSource(self, fileName):
        '''
        Parse a single file and populate shader lib
        '''
        print '=> parsing {}'.format(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()

        # all blocks must be closed
        if self.current is not None:
            util.fmtError('missing @end at end of file')
Exemplo n.º 18
0
 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)
Exemplo n.º 19
0
 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)
Exemplo n.º 20
0
 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))
Exemplo n.º 21
0
 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))
Exemplo n.º 22
0
 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
Exemplo n.º 23
0
 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            
Exemplo n.º 24
0
 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
Exemplo n.º 25
0
 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
Exemplo n.º 26
0
 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))
Exemplo n.º 27
0
 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
Exemplo n.º 28
0
 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        
Exemplo n.º 29
0
 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            
Exemplo n.º 30
0
 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        
Exemplo n.º 31
0
 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))
Exemplo n.º 32
0
 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)
Exemplo n.º 33
0
 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