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: tool.py,v 1.6 2005/03/31 17:20:01 mbaas Exp $
-
- ## \file tool.py
- ## Contains the Tool base class.
-
- import os, os.path, sys, optparse, re
- import pluginmanager
- from eventmanager import eventManager
- from scene import getScene
- from targetcamera import TargetCamera
- from Interfaces import *
- from cmds import *
- import application
-
-
- # Tool
- class Tool:
- """Base class for command tools that process a cgkit scene.
-
- Derived classes have to implement the init() and action() method.
- The options are parsed in the constructor. To start the tool, the
- run() method has to be called. This method does the following:
-
- - Call init()
- - Check if input files are given
- - Load plugins
- - Load input files
- - Get or create a camera
- - Call action()
-
- Attributes:
-
- - time_start
- - time_end
- - frame_start
- - frame_end
-
- The global timer will be initialized with the frame rate and the
- start time.
- """
-
- def __init__(self, defaultoptionvar=None):
- """Constructor.
-
- defaultoptionvar is the name of an environment variable that
- contains the default options.
- """
-
- # Create the option parser, ...
- self.optparser = self.createOptionParser()
- # set the options...
- self.setOptions(self.optparser)
-
- scene = getScene()
- timer = scene.timer()
-
- # Parse the default options
- defaultopts = None
- if defaultoptionvar!=None:
- if defaultoptionvar in os.environ:
- optstring = os.environ[defaultoptionvar]
- args = optstring.split()
- defaultopts, dummy = self.optparser.parse_args(args)
-
- # ...and parse the command line. The options are in "options"
- self.options, self.args = self.optparser.parse_args(values=defaultopts)
-
- # Print default options
- if self.options.verbose:
- print "Python",sys.version
- if defaultoptionvar!=None:
- if defaultoptionvar in os.environ:
- print "Default options in %s: %s"%(defaultoptionvar, os.environ[defaultoptionvar])
- else:
- print "Environment variable %s not set."%defaultoptionvar
-
- # Determine screen resolution...
- self._no_resolution_specified = False
- if self.options.width==None:
- self.options.width = 640
- self._no_resolution_specified = True
- if self.options.height==None:
- self.options.height = int(self.options.width*3.0/4)
-
- # Set the global application object to this tool class
- application._app = self
-
- # init
- def init(self):
- pass
-
- # action
- def action(self):
- pass
-
-
- # createOptionParser
- def createOptionParser(self):
- """Create and OptionParser instance.
-
- \return Option parser.
- """
- usage = "usage: %prog [options] inputfiles"
- return optparse.OptionParser(usage)
-
- # setOptions
- def setOptions(self, optparser):
- """Set the options.
-
- \param optparser (\c OptionParser) Option parser
- """
- optparser.add_option("-f", "--fps", type="float", default=30,
- help="Frame rate")
- optparser.add_option("-W", "--width", type="int", default=None,
- help="Screen width")
- optparser.add_option("-H", "--height", type="int", default=None,
- help="Screen height")
- optparser.add_option("-p", "--plugin", action="append", default=[],
- help="Load a plugin file or directory")
- optparser.add_option("-v", "--verbose", action="store_true", default=False,
- help="Output info messages")
- optparser.add_option("-c", "--camera", metavar="NAME",
- help="Select a camera")
- optparser.add_option("-b", "--begin", metavar="TIME",
- help="Specify time or frame where to begin")
- optparser.add_option("-e", "--end", metavar="TIME",
- help="Specify time or frame where to end")
- optparser.add_option("-U", "--up", metavar="AXIS",
- help="Specify the up axis ('y' or 'z')")
- optparser.add_option("-O", "--option", action="append", default=[],
- help="Add a global scene option")
- optparser.add_option("-t", "--set-time", action="store_true", default=False,
- help="Set starting time directly instead of stepping there")
-
- # run
- def run(self):
- """Run the tool.
-
- This method calls the init() and action() method.
- """
-
- # Custom initialization
- self.init()
-
- # No input file given? Then print the help page and exit
- if len(self.args)==0:
- self.optparser.print_help()
- return
-
- # Load plugins
- self.loadPlugins()
-
- # Load the input files...
- for filename in self.args:
- if self.options.verbose:
- print 'Loading "%s"...'%filename
- load(filename)
-
- # Convert global settings into command line options
- self.setOptionsFromGlobals()
-
- self.cam = self.getCamera()
-
- self.action()
-
- getScene().clear()
-
- # setOptionsFromGlobals
- def setOptionsFromGlobals(self):
- """Convert global settings into command line options.
-
- This method is called by the run() method after the input
- files have been read. The method inspects the global settings
- and modifies the command line options as appropriate.
- """
-
- scene = getScene()
- timer = scene.timer()
-
- # Set additional global options
- for s in self.options.option:
- f = s.split("=")
- name = f[0]
- val = "=".join(f[1:])
- scene.setGlobal(name, val)
-
- # Set framerate
- self.options.fps = scene.getGlobal("fps", self.options.fps)
-
- # Set resolution
- if self._no_resolution_specified:
- w,h,a = self.getResolution()
- self.options.width = w
- self.options.height = h
- self.options.aspect = a
-
- # Camera
- self.options.camera = scene.getGlobal("camera", self.options.camera)
-
- # Set up direction
- if self.options.up!=None:
- up = self.options.up.lower()
- if up=="y":
- scene.up = (0,1,0)
- elif up=="z":
- scene.up = (0,0,1)
- else:
- raise ValueError, "Invalid 'up' direction: '%s' (should be 'y' or 'z')"%self.options.up
-
- # Set the frame rate
- timer.fps = self.options.fps
-
- # Determine end time
- self.time_end = None
- self.frame_end = None
- if self.options.end!=None:
- val, unit = self._parseTimeStr(self.options.end)
- if unit=="f":
- scene.timer().frame = val
- else:
- scene.timer().time = val
- self.time_end = timer.time
- self.frame_end = timer.frame
-
- # Determine start time (which will be set on the timer)
- self.time_start = 0.0
- self.frame_start = 0.0
- if self.options.begin!=None:
- val, unit = self._parseTimeStr(self.options.begin)
- if unit=="f":
- scene.timer().frame = val
- else:
- scene.timer().time = val
- self.time_start = timer.time
- self.frame_start = timer.frame
-
- # Set the timer to the start time...
- # (either by stepping there or by setting it directly)
- if self.options.set_time:
- # Set the time directly
- timer.time = self.time_start
- else:
- # Step to the start time (so that any simulation, etc. is properly
- # done)
- timer.time = 0
- while self.time_start-timer.time>1E-5:
- timer.step()
-
- if self.time_end==None:
- te = "<inf>"
- fe = "<inf>"
- else:
- te = "%1.2fs"%self.time_end
- fe = "%d"%self.frame_end
- if self.options.verbose:
- print "Time range: %1.2fs - %s (frames %d - %s)"%(self.time_start, te, self.frame_start, fe)
-
-
- # loadPlugins
- def loadPlugins(self):
- """Load plugins.
-
- The plugins specified in the environment variable CGKIT_PLUGIN_PATH
- and in the command line are loaded.
- """
-
- s = os.environ.get("CGKIT_PLUGIN_PATH", "")
- pluginsvar = splitPaths(s)
-
- lst = getattr(self.options, "plugin", [])
- s = ";".join(lst)
- s = s.replace(",", ";")
- pluginsopt = splitPaths(s)
-
- plugins = pluginsvar + pluginsopt
-
- descs = pluginmanager.importPlugins(plugins)
- for desc in descs:
- if desc.status!=pluginmanager.STATUS_OK:
- sys.stderr.write(70*"-"+"\n")
- sys.stderr.write('ERROR: Loading plugin "%s" failed:\n'%os.path.basename(desc.filename))
- sys.stderr.write("\n"+desc.traceback)
- sys.stderr.write(70*"-"+"\n")
-
- # getCamera
- def getCamera(self):
- """Get or create a camera object.
- """
-
- scene = getScene()
-
- cname = self.options.camera
-
- # Search for a camera...
- cam = None
- for obj in scene.walkWorld():
- prots = obj.protocols()
- if ICamera in prots:
- if obj.name==cname or cname==None :
- cam = obj
- break
-
- if cname!=None and cam==None:
- raise ValueError, 'Camera "%s" not found.'%cname
-
- # No camera? Then create a default camera...
- if cam==None:
- if self.options.verbose:
- print "No camera set, using a default camera."
- bbmin, bbmax = scene.boundingBox().getBounds()
- dif = bbmax-bbmin
- b1 = scene.up.ortho()
- b2 = scene.up.cross(b1)
- pos = dif.length()*(0.5*b1+b2) + (bbmax.z+0.5*dif.z)*scene.up
- if abs(dif.z)<0.0001:
- pos += 0.8*dif.length()*scene.up
- cam = TargetCamera(pos = pos,
- target = 0.5*(bbmin+bbmax)-0.2*(dif.z*scene.up),
- fov = 50)
- else:
- if self.options.verbose:
- print "Camera:",cam.name
-
- return cam
-
- # getResolution
- def getResolution(self):
- """Read the global resolution setting.
-
- Returns a tuple (width, height, pixel aspect)
- """
- res = getScene().getGlobal("resolution", (640,480))
- try:
- if len(res)==2:
- w,h = res
- aspect = 1
- elif len(res)==3:
- w,h,aspect = res
- else:
- raise Exception
- except:
- print >>sys.stderr, "Error: Invalid resolution setting:",res
- w,h,aspect = 640,480,1
- return w,h,aspect
-
- # translateKeyWordOpt
- def translateKeyWordOpt(self, opt, dic, msg):
- """Translates an option value from keyword to internal value.
-
- opt is the value of the option as specified by the user.
- dic is a dictionary that translates keywords to internal values.
- msg is an error message that will be passed to the ValueError
- exception. msg must contain the sub string "%s" that will be
- replaced with the invalid option value.
- """
-
- if opt==None:
- opt2 = None
- else:
- opt2 = opt.lower()
-
- if dic.has_key(opt2):
- return dic[opt2]
- else:
- raise ValueError, msg%opt
-
-
- ## protected:
-
- # _parseTimeStr
- def _parseTimeStr(self, s):
- """Split a string containing a time value into the value and unit.
-
- Returns a tuple (value, unit).
- """
- m = re.search("[a-z]*$", s)
- unit = s[m.start():]
- val = float(s[:m.start()])
- if unit=="":
- unit="f"
- if unit not in ["f", "s"]:
- raise ValueError, "Unknown time unit: '%s'"%unit
- return val,unit
-
-
-