Beispiel #1
0
    def getShaderInfo(self, shader):
        """Read the shader parameters from a given shader.
        """
        sloargs = self._sloargs
        
        # Split path and file name
        shaderPath,shaderFileName = os.path.split(shader)
        if shaderPath=="":
            shaderPath = "."
        # Remove the extension
        shader = os.path.splitext(shaderFileName)[0]

        sloargs.Slo_SetPath(shaderPath)
        # Try the shader name with extension first...
        if sloargs.Slo_SetShader(shaderFileName)!=0:
            # If the above failed, try the shader name without extension (prman)...
            if sloargs.Slo_SetShader(shader)!=0:
                raise IOError('Failed to open shader "%s"'%shader)
        
        shaderName = sloargs.Slo_GetName()
        shaderType = sloargs.Slo_TypetoStr(sloargs.Slo_GetType())
        metaData = self._getMetaData()
        params = []
        numParams = sloargs.Slo_GetNArgs()
        for i in range(1, numParams+1):
            res = sloargs.Slo_GetArgById(i)
            symdef = res.contents
            
            if sloargs.Slo_StortoStr(symdef.storage).startswith("output"):
                output = "output"
            else:
                output = ""
            storage = sloargs.Slo_DetailtoStr(symdef.detail)
            paramType = sloargs.Slo_TypetoStr(symdef.type)
            arrLen = symdef.arraylen
            if arrLen==0:
                arrLen = None
            name = symdef.name
            space = self._getSpace(symdef)
            if space=="":
                space = None
            defaultVal = self._getDefaultVal(symdef)
            params.append(_ShaderParam(output,storage,paramType,arrLen,name,space,defaultVal))
            
        sloargs.Slo_EndShader()
        return [_ShaderInfo(type=shaderType, name=shaderName, params=params, meta=metaData)]
Beispiel #2
0
def slparams(slfile=None, cpp=None, cpperrstream=sys.stderr, slname=None, includedirs=None, defines=None):
    """Extracts the shader parameters from a RenderMan Shader file.

    The argument *slfile* is either the name of a compiled shader, the name of
    the shader source file (``*.sl``) or a file-like object that provides the
    shader sources.
    
    *cpp* determines how the shader source is preprocessed.
    It can either be a string containing the name of an external
    preprocessor tool (such as ``cpp``) that must take the file name as
    parameter and dump the preprocessed output to stdout or it can be
    a callable that takes *slfile* and *cpperrstream* as input and returns
    the preprocessed sources as a string. If the external
    preprocessor does not produce any data a :exc:`PreprocessorNotFound`
    exception is thrown.
    The error stream of the preprocessor is written to the object
    specified by *cpperrstream* which must have a :meth:`write()`
    method. If *cpperrstream* is ``None``, the error stream is ignored.

    If *cpp* is ``None`` a simple internal preprocessor based on the
    :mod:`simplecpp` module is used.
    The *slname* argument is an alias for *slfile*, it is only available
    for backwards compatibility.
    
    *includedirs* is a list of strings that contain directories where to
    look for include files. *defines* is a list of tuples (*name*, *value*)
    that specify the predefined symbols to use.
    
    The function returns a list of shader info objects. These objects have
    four attributes:
    
    - ``type``: The type of the shader (surface, displacement, etc.)
    - ``name``: The name of the shader
    - ``params``: The shader parameters (see below)
    - ``meta``: The shader meta data. How exactly meta data is specified depends
      on the renderer you are using.
     
    The parameters are given as a list of shader parameter objects
    describing each parameter. A shader parameter object has the
    following attributes:

    - ``outputSpec``: The output specifier (either ``"output"`` or an empty string)
    - ``storage``: The storage class (``"uniform"`` or ``"varying"``)
    - ``type``: The parameter type
    - ``size``: The array length or ``None`` if the parameter is not an array
    - ``name``: The name of the parameter
    - ``space``: The space in which a point-like type was defined
    - ``default``: The "raw" default value. If the input was a shader source file,
      this will always be a string containing an expression. If the input was
      a compiled shader this will already be an appropriate Python value.
      You should never use this value directly, but always use :func:`convertdefault()`
      to obtain a value which can be further processed. This way, your code
      will work for both, compiled shaders and shader source files.
    
    For backwards compatibility, the shader info object behaves like a
    3-tuple (*type*, *name*, *params*). The meta data can only be accessed via
    name though. The shader parameter objects can also be used like 7-tuples
    containing the above data (in the order given above).
    
    Example (output slightly reformatted for better readability)::

      >>> from cgkit import slparams
      >>> shaders = lparams.slparams("plastic.sl")
      >>> print shaders
      [('surface', 'plastic', 
        [('', 'uniform', 'float', None, 'Ka', None, '1'),
         ('', 'uniform', 'float', None, 'Kd', None, '0.5'),
         ('', 'uniform', 'float', None, 'Ks', None, '0.5'),
         ('', 'uniform', 'float', None, 'roughness', None, '0.1'),
         ('', 'uniform', 'color', None, 'specularcolor', 'rgb', '1')])]
      >>> shaders[0].type
      'surface'
      >>> shaders[0].name
      'plastic'
      >>> for param in shaders[0].params: print param.name
      ... 
      Ka
      Kd
      Ks
      roughness
      specularcolor
      >>> shaders[0].meta
      {}

    The parser used inside this function was generated using the parser generator
    `Yapps <http://theory.stanford.edu/~amitp/Yapps/>`_  by Amit Patel.
    """

    if slname is not None:
        slfile = slname
    if slfile is None:
        return []

    # Check if the input file is a string referring to a compiled shader
    # (suffix != .sl). If so, use the sloargs module to get the shader information
    if isinstance(slfile, basestring):
        if os.path.splitext(slfile)[1].lower() != ".sl":
            if _has_sloargs:
                return sloargs.slparams(slfile)
            else:
                raise _sloargs_importerror

    # Run the preprocessor on the input file...

    slsrc = preprocess(cpp, slfile, cpperrstream=cpperrstream, defines=defines, includedirs=includedirs)
    f = StringIO.StringIO(slsrc)

    # ...and filter it, so that only the shader and function
    # definitions remain...
    filter = _SLfilter()
    sltokenize.tokenize(f.readline, filter.eater)
    f.close()

    #    print filter.SLsource

    # Parse the filtered source code...
    scanner = _slparser._SLParserBaseScanner(filter.SLsource)
    parser = _SLParser(scanner)

    #    return wrap_error_reporter(parser, "definitions")

    try:
        lst = getattr(parser, "definitions")()
        # Turn the 3-tuples into _ShaderInfo objects
        return map(lambda tup: _ShaderInfo(*tup), lst)
    except _slparser.NoMoreTokens, err:
        raise NoMoreTokens, "No more tokens"