home *** CD-ROM | disk | FTP | other *** search
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the Python Computer Graphics Kit.
- #
- # The Initial Developer of the Original Code is Matthias Baas.
- # Portions created by the Initial Developer are Copyright (C) 2004
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
- # $Id: component.py,v 1.3 2005/08/15 15:47:56 mbaas Exp $
-
- ## \file component.py
- ## Contains the Component base class.
-
- from _core import Component as _Component
- from Interfaces import ISceneItem
- import protocols, copy, inspect, re
- from slots import *
- import scene
-
- # Component
- class Component(_Component):
- """Base component class.
-
- Attributes:
-
- - name (\c str): The name of the component
- """
-
- protocols.advise(instancesProvide=[ISceneItem])
-
- def __init__(self, name="", auto_insert=True):
- _Component.__init__(self, name)
-
- if auto_insert:
- scene.getScene().insert(self)
-
- def protocols(self):
- return [ISceneItem]
-
- def connect(self, srcslot, dstslot):
- dstslot.setController(srcslot)
-
- ############
-
- def _parseFuncDecl(funcdecl):
- """Parse a function declaration string.
-
- The syntax of the string is like a C function declaration:
-
- <result_type> <func_name>(<parameters>)
-
- Example: "vec3 f(double x, double x, double z)"
-
- The function name may be left out
-
- The function returns a tuple (result_type, func_name, params)
- where params is a list of tuples (name, type, default). The name of a
- parameter might also be empty.
- """
- funcdecl = funcdecl.strip()
-
- # Parse the result type...
- m = re.match("[a-zA-Z0-9]+ ", funcdecl)
- if m==None:
- raise SyntaxError, "No valid return type found"
-
- restype = funcdecl[m.start():m.end()].strip()
-
- # Parse the function name...
- s = funcdecl[m.end():]
- i = s.find("(")
- if i==-1:
- raise SyntaxError, "Parameter block is missing"
- funcname = s[:i].strip()
-
- # Parse the arguments...
- args = s[i+1:-1].split(",")
- inputs = []
- for s in args:
- s = s.strip()
- f = s.split()
- if len(f)==1:
- type = f[0]
- name = ""
- elif len(f)==2:
- type,name = f
- else:
- raise SyntaxError, "Invalid parameter declaration: '%s'"%s
- inputs.append((name,type,None))
-
- return restype, funcname, inputs
-
- def _inspectFuncDecl(func):
- """Determine the function declaration from the function itself.
-
- The function returns a tuple (result_type, func_name, params)
- where params is a list of tuples (name, type, default).
-
- result_type and params may also be None if they cannot be determined
- (i.e. if not every argument to the function has a default value).
- """
- # Extract function name...
- funcname = func.__name__
-
- args,va,vkw,defaults = inspect.getargspec(func)
- # Only proceed if every argument has a default value
- if defaults==None or len(args)!=len(defaults):
- return None, funcname, None
-
- # Extract the argument types (=the types of the default values)
- inputs = []
- for name, value in zip(args, defaults):
- type = value.__class__.__name__
- if type=="float":
- type = "double"
- inputs.append((name, type, value))
-
- # Determine the result type
- v = func()
- restype = v.__class__.__name__
- if restype=="float":
- restype = "double"
-
- return restype, funcname, inputs
-
-
- def _defaultValueLiteral(type, default):
- """Convert a value into a string so that it can be executed again.
- """
- if default==None:
- return ""
-
- if type in ["vec3", "vec4"]:
- return "%s(%s)"%(type,default)
- else:
- return "%s"%default
-
-
- def createFunctionComponentSource(clsname, restype, funcname, inputs):
- """Create a string that creates a component class.
-
- """
-
- res = """from cgkit import _core
- from cgkit.scene import getScene
-
- class %s(Component):
-
- def __init__(self):
- Component.__init__(self, func.__name__)
- """%(clsname)
-
- # Create output slot
- outname = "output"
- slotclassname = "Procedural%sSlot"%restype.capitalize()
- slotname = "%s_slot"%outname
- res += " self.%s = %s(self.compute%s)\n"%(slotname, slotclassname, outname.capitalize())
- res += ' self.addSlot("%s", self.%s)\n'%(outname, slotname)
-
- # Create input slots
- for name, type, default in inputs:
- slotclassname = "%sSlot"%type.capitalize()
- slotname = "%s_slot"%name
- res += " self.%s = %s(%s)\n"%(slotname, slotclassname, _defaultValueLiteral(type, default))
- res += ' self.addSlot("%s", self.%s)\n'%(name, slotname)
- res += " self.%s.addDependent(self.%s_slot)\n"%(slotname, outname)
- if name=="time" and type=="double":
- res += " getScene().timer().time_slot.connect(self.%s)\n"%slotname
-
- # res += " self._func_obj = %s\n"%funcname
- res += " self._func_obj = func\n"
-
- res += '\n exec slotPropertyCode("%s")\n'%(outname)
- for name,type,default in inputs:
- res += ' exec slotPropertyCode("%s")\n'%(name)
-
- res += """\n def compute%s(self):
- return self._func_obj("""%(outname.capitalize())
-
- inames = map(lambda x: "%s=self.%s"%(x[0],x[0]), inputs)
- res += ", ".join(inames)
- res += ")\n"
-
- return res
-
-
- # createFunctionComponent
- def createFunctionComponent(func, funcdeclaration=None):
-
- if funcdeclaration==None:
- restype, funcname, inputs = _inspectFuncDecl(func)
- if restype==None:
- raise ValueError, "Cannot determine the types of the arguments and the return value."
- else:
- restype, funcname, inputs = _parseFuncDecl(funcdeclaration)
-
- if funcname==None or funcname=="":
- funcname = func.__name__
-
- clsname = funcname.capitalize()
- s = createFunctionComponentSource(clsname, restype, funcname, inputs)
- ns = copy.copy(globals())
- ns["func"]=func
- exec s in ns
- return ns[clsname]
-
-