forked from bartvdbraak/blender
6b65e39a44
- switching the define on in buildsystems (NaN, auto and msvc are done) - again import _Blender, which is the C module, from the Python modules
280 lines
7.9 KiB
Python
280 lines
7.9 KiB
Python
"""The Blender Ipo module
|
|
|
|
This module provides access to **Ipo** objects in Blender.
|
|
|
|
An Ipo object is a datablock of IpoCurves which control properties of
|
|
an object in time.
|
|
|
|
Note that IpoCurves assigned to rotation values (which must be specified
|
|
in radians) appear scaled in the IpoWindow (which is in fact true, due
|
|
to the fact that conversion to an internal unit of 10.0 angles happens).
|
|
|
|
Example::
|
|
|
|
from Blender import Ipo, Object
|
|
|
|
ipo = Ipo.New('Object', 'ObIpo') # Create object ipo with name 'ObIpo'
|
|
curve = ipo.addCurve('LocY') # add IpoCurve for LocY
|
|
curve.setInterpolation('Bezier') # set interpolation type
|
|
curve.setExtrapolation('CyclicLinear') # set extrapolation type
|
|
|
|
curve.addBezier((0.0, 0.0)) # add automatic handle bezier point
|
|
curve.addBezier((20.0, 5.0), 'Free', (10.0, 4.0)) # specify left handle, right auto handle
|
|
curve.addBezier((30.0, 1.0), 'Vect') # automatic split handle
|
|
curve.addBezier((100.0, 1.0)) # auto handle
|
|
|
|
curve.update() # recalculate curve handles
|
|
|
|
curve.eval(35.0) # evaluate curve at 35.0
|
|
|
|
ob = Object.get('Plane')
|
|
ob.setIpo(ipo) # assign ipo to object
|
|
"""
|
|
|
|
import _Blender.Ipo as _Ipo
|
|
|
|
import shadow
|
|
|
|
_RotIpoCurves = ["RotX", "RotY", "RotZ", "dRotX", "dRotY", "dRotZ"]
|
|
|
|
_radian_factor = 5.72957814 # 18.0 / 3.14159255
|
|
|
|
def _convertBPoint(b):
|
|
f = _radian_factor
|
|
newb = BezierPoint()
|
|
p = b.pt
|
|
q = newb.pt
|
|
q[0], q[1] = (p[0], f * p[1])
|
|
p = b.h1
|
|
q = newb.h1
|
|
q[0], q[1] = (p[0], f * p[1])
|
|
p = b.h2
|
|
q = newb.h2
|
|
q[0], q[1] = (p[0], f * p[1])
|
|
return newb
|
|
|
|
|
|
class IpoBlock(shadow.shadowEx):
|
|
"""Wrapper for Blender Ipo DataBlock
|
|
|
|
Attributes
|
|
|
|
curves -- list of owned IpoCurves
|
|
"""
|
|
def get(self, channel = None):
|
|
"""Returns curve with channel identifier 'channel', which is one of the properties
|
|
listed in the Ipo Window, 'None' if not found.
|
|
If 'channel' is not specified, all curves are returned in a list"""
|
|
if channel:
|
|
for c in self._object.curves:
|
|
if c.name == channel:
|
|
return IpoCurve(c)
|
|
return None
|
|
else:
|
|
return map(lambda x: IpoCurve(x), self._object.curves)
|
|
|
|
def __getitem__(self, k):
|
|
"""Emulates dictionary syntax, e.g. ipocurve = ipo['LocX']"""
|
|
curve = self.get(k)
|
|
if not curve:
|
|
raise KeyError, "Ipo does not have a curve for channel %s" % k
|
|
return curve
|
|
|
|
def __setitem__(self, k, val):
|
|
"""Emulates dictionary syntax, e.g. ipo['LocX'] = ipocurve"""
|
|
c = self.addCurve(k, val)
|
|
|
|
has_key = get # dict emulation
|
|
|
|
items = get # dict emulation
|
|
|
|
def keys(self):
|
|
return map(lambda x: x.name, self.get())
|
|
|
|
def addCurve(self, channel, curve = None):
|
|
"""Adds a curve of channel type 'channel' to the Ipo Block. 'channel' must be one of
|
|
the object properties listed in the Ipo Window. If 'curve' is not specified,
|
|
an empty curve is created, otherwise, the existing IpoCurve 'curve' is copied and
|
|
added to the IpoBlock 'self'.
|
|
In any case, the added curve is returned.
|
|
"""
|
|
if curve:
|
|
if curve.__class__.__name__ != "IpoCurve":
|
|
raise TypeError, "IpoCurve expected"
|
|
c = self._object.addCurve(channel, curve._object)
|
|
|
|
### RotIpo conversion hack
|
|
if channel in _RotIpoCurves:
|
|
print "addCurve, converting", curve.name
|
|
c.points = map(_convertBPoint, curve.bezierPoints)
|
|
else:
|
|
c.points = curve.bezierPoints
|
|
else:
|
|
c = self._object.addCurve(channel)
|
|
return IpoCurve(c)
|
|
|
|
_getters = { 'curves' : get }
|
|
|
|
class BezierPoint:
|
|
"""BezierPoint object
|
|
|
|
Attributes
|
|
|
|
pt -- Coordinates of the Bezier point
|
|
|
|
h1 -- Left handle coordinates
|
|
|
|
h2 -- Right handle coordinates
|
|
|
|
h1t -- Left handle type (see IpoCurve.addBezier(...) )
|
|
|
|
h2t -- Right handle type
|
|
"""
|
|
|
|
BezierPoint = _Ipo.BezTriple # override
|
|
|
|
class IpoCurve(shadow.shadowEx):
|
|
"""Wrapper for Blender IpoCurve
|
|
|
|
Attributes
|
|
|
|
bezierPoints -- A list of BezierPoints (see class BezierPoint),
|
|
defining the curve shape
|
|
"""
|
|
|
|
InterpolationTypes = _Ipo.InterpolationTypes
|
|
ExtrapolationTypes = _Ipo.ExtrapolationTypes
|
|
|
|
def __init__(self, object):
|
|
self._object = object
|
|
self.__dict__['bezierPoints'] = self._object.points
|
|
|
|
def __getitem__(self, k):
|
|
"""Emulate a sequence of BezierPoints"""
|
|
print k, type(k)
|
|
return self.bezierPoints[k]
|
|
|
|
def __repr__(self):
|
|
return "[IpoCurve %s]" % self.name
|
|
|
|
def __len__(self):
|
|
return len(self.bezierPoints)
|
|
|
|
def eval(self, time):
|
|
"""Returns float value of curve 'self' evaluated at time 'time' which
|
|
must be a float."""
|
|
return self._object.eval(time)
|
|
|
|
def addBezier(self, p, leftType = 'Auto', left = None, rightType = None, right = None):
|
|
"""Adds a Bezier triple to the IpoCurve.
|
|
|
|
The following values are float tuples (x,y), denoting position of a control vertex:
|
|
|
|
p -- The position of the Bezier point
|
|
|
|
left -- The position of the leftmost handle
|
|
|
|
right -- The position of the rightmost handle
|
|
|
|
'leftType', 'rightType' must be one of:
|
|
|
|
"Auto" -- automatic handle calculation. In this case, 'left' and 'right' don't need to be specified
|
|
|
|
"Vect" -- automatic split handle calculation. 'left' and 'right' are disregarded.
|
|
|
|
"Align" -- Handles are aligned automatically. In this case, 'right' does not need to be specified.
|
|
|
|
"Free" -- Handles can be set freely - this requires both arguments 'left' and 'right'.
|
|
|
|
"""
|
|
|
|
b = _Ipo.BezTriple()
|
|
b.pt[0], b.pt[1] = (p[0], p[1])
|
|
b.h1t = leftType
|
|
|
|
if rightType:
|
|
b.h2t = rightType
|
|
else:
|
|
b.h2t = leftType
|
|
|
|
if left:
|
|
b.h1[0], b.h1[1] = (left[0], left[1])
|
|
|
|
if right:
|
|
b.h2[0], b.h2[1] = (right[0], right[1])
|
|
|
|
self.__dict__['bezierPoints'].append(b)
|
|
return b
|
|
|
|
def update(self, noconvert = 0):
|
|
# This is an ugly fix for the 'broken' storage of Rotation
|
|
# ipo values. The angles are stored in units of 10.0 degrees,
|
|
# which is totally inconsistent with anything I know :-)
|
|
# We can't (at the moment) change the internals, so we
|
|
# apply a conversion kludge..
|
|
if self._object.name in _RotIpoCurves and not noconvert:
|
|
points = map(_convertBPoint, self.bezierPoints)
|
|
else:
|
|
points = self.bezierPoints
|
|
self._object.points = points
|
|
self._object.update()
|
|
|
|
def getInterpolationType(self, ipotype):
|
|
"Returns the Interpolation type - see also IpoCurve.InterpolationTypes"
|
|
return self._object.getInterpolationType()
|
|
|
|
def setInterpolationType(self, ipotype):
|
|
"""Sets the interpolation type which must be one of IpoCurve.InterpolationTypes"""
|
|
try:
|
|
self._object.setInterpolationType(ipotype)
|
|
except:
|
|
raise TypeError, "must be one of %s" % self.InterpolationTypes.keys()
|
|
|
|
def getExtrapolationType(self, ipotype):
|
|
"Returns the Extrapolation type - see also IpoCurve.ExtrapolationTypes"
|
|
return self._object.getExtrapolationType()
|
|
|
|
def setExtrapolationType(self, ipotype):
|
|
"""Sets the interpolation type which must be one of IpoCurve.ExtrapolationTypes"""
|
|
try:
|
|
self._object.setInterpolationType(ipotype)
|
|
except:
|
|
raise TypeError, "must be one of %s" % self.ExtrapolationTypes.keys()
|
|
|
|
|
|
def New(blocktype, name = None):
|
|
"""Returns a new IPO block of type 'blocktype' which must be one of:
|
|
["Object", "Camera", "World", "Material"]
|
|
"""
|
|
if name:
|
|
i = _Ipo.New(blocktype, name)
|
|
else:
|
|
i = _Ipo.New(blocktype)
|
|
return IpoBlock(i)
|
|
|
|
def Eval(ipocurve, time): # emulation code
|
|
"""This function is just there for compatibility.
|
|
Use IpoCurve.eval(time) instead"""
|
|
return ipocurve.eval(time)
|
|
|
|
def Recalc(ipocurve): # emulation code
|
|
"""This function is just there for compatibility. Note that Ipos
|
|
assigned to rotation values will *not* get converted to the proper
|
|
unit of radians.
|
|
In the new style API, use IpoCurve.update() instead"""
|
|
return ipocurve.update(1)
|
|
|
|
def get(name = None):
|
|
"""If 'name' given, the Ipo 'name' is returned if existing, 'None' otherwise.
|
|
If no name is given, a list of all Ipos is returned"""
|
|
if name:
|
|
ipo = _Ipo.get(name)
|
|
if ipo:
|
|
return IpoBlock(ipo)
|
|
else:
|
|
return None
|
|
else:
|
|
return shadow._List(_Ipo.get(), IpoBlock)
|
|
|
|
Get = get # emulation
|