mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-25 20:52:26 -06:00
443 lines
15 KiB
Python
443 lines
15 KiB
Python
|
"""FunctionInterval module: contains the FunctionInterval class"""
|
||
|
|
||
|
__all__ = ['FunctionInterval', 'EventInterval', 'AcceptInterval', 'IgnoreInterval', 'ParentInterval', 'WrtParentInterval', 'PosInterval', 'HprInterval', 'ScaleInterval', 'PosHprInterval', 'HprScaleInterval', 'PosHprScaleInterval', 'Func', 'Wait']
|
||
|
|
||
|
from pandac.PandaModules import *
|
||
|
from direct.showbase.MessengerGlobal import *
|
||
|
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||
|
import Interval
|
||
|
import types
|
||
|
|
||
|
|
||
|
#############################################################
|
||
|
### ###
|
||
|
### See examples of function intervals in IntervalTest.py ###
|
||
|
### ###
|
||
|
#############################################################
|
||
|
|
||
|
class FunctionInterval(Interval.Interval):
|
||
|
# Name counter
|
||
|
functionIntervalNum = 1
|
||
|
|
||
|
# Keep a list of function intervals currently in memory for
|
||
|
# Control-C-Control-V redefining. These are just weakrefs so they
|
||
|
# should not cause any leaks.
|
||
|
if __debug__:
|
||
|
import weakref
|
||
|
FunctionIntervals = weakref.WeakKeyDictionary()
|
||
|
|
||
|
@classmethod
|
||
|
def replaceMethod(self, oldFunction, newFunction):
|
||
|
import types
|
||
|
count = 0
|
||
|
for ival in self.FunctionIntervals:
|
||
|
# print 'testing: ', ival.function, oldFunction
|
||
|
# Note: you can only replace methods currently
|
||
|
if type(ival.function) == types.MethodType:
|
||
|
if (ival.function.im_func == oldFunction):
|
||
|
# print 'found: ', ival.function, oldFunction
|
||
|
ival.function = types.MethodType(newFunction,
|
||
|
ival.function.im_self,
|
||
|
ival.function.im_class)
|
||
|
count += 1
|
||
|
return count
|
||
|
|
||
|
# create FunctionInterval DirectNotify category
|
||
|
notify = directNotify.newCategory('FunctionInterval')
|
||
|
|
||
|
# Class methods
|
||
|
def __init__(self, function, **kw):
|
||
|
"""__init__(function, name = None, openEnded = 1, extraArgs = [])
|
||
|
"""
|
||
|
name = kw.pop('name', None)
|
||
|
openEnded = kw.pop('openEnded', 1)
|
||
|
extraArgs = kw.pop('extraArgs', [])
|
||
|
|
||
|
# Record instance variables
|
||
|
self.function = function
|
||
|
|
||
|
# Create a unique name for the interval if necessary
|
||
|
if name is None:
|
||
|
name = self.makeUniqueName(function)
|
||
|
assert isinstance(name, str)
|
||
|
|
||
|
# Record any arguments
|
||
|
self.extraArgs = extraArgs
|
||
|
self.kw = kw
|
||
|
# Initialize superclass
|
||
|
# Set openEnded true if privInitialize after end time cause interval
|
||
|
# function to be called. If false, privInitialize calls have no effect
|
||
|
# Event, Accept, Ignore intervals default to openEnded = 0
|
||
|
# Parent, Pos, Hpr, etc intervals default to openEnded = 1
|
||
|
Interval.Interval.__init__(self, name, duration = 0.0, openEnded = openEnded)
|
||
|
|
||
|
# For rebinding, let's remember this function interval on the class
|
||
|
if __debug__:
|
||
|
self.FunctionIntervals[self] = 1
|
||
|
|
||
|
@staticmethod
|
||
|
def makeUniqueName(func, suffix = ''):
|
||
|
name = 'Func-%s-%d' % (getattr(func, '__name__', str(func)), FunctionInterval.functionIntervalNum)
|
||
|
FunctionInterval.functionIntervalNum += 1
|
||
|
if suffix:
|
||
|
name = '%s-%s' % (name, str(suffix))
|
||
|
return name
|
||
|
|
||
|
def privInstant(self):
|
||
|
# Evaluate the function
|
||
|
self.function(*self.extraArgs, **self.kw)
|
||
|
# Print debug information
|
||
|
self.notify.debug(
|
||
|
'updateFunc() - %s: executing Function' % self.name)
|
||
|
|
||
|
|
||
|
### FunctionInterval subclass for throwing events ###
|
||
|
class EventInterval(FunctionInterval):
|
||
|
# Initialization
|
||
|
def __init__(self, event, sentArgs=[]):
|
||
|
"""__init__(event, sentArgs)
|
||
|
"""
|
||
|
def sendFunc(event = event, sentArgs = sentArgs):
|
||
|
messenger.send(event, sentArgs)
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, sendFunc, name = event)
|
||
|
|
||
|
### FunctionInterval subclass for accepting hooks ###
|
||
|
class AcceptInterval(FunctionInterval):
|
||
|
# Initialization
|
||
|
def __init__(self, dirObj, event, function, name = None):
|
||
|
"""__init__(dirObj, event, function, name)
|
||
|
"""
|
||
|
def acceptFunc(dirObj = dirObj, event = event, function = function):
|
||
|
dirObj.accept(event, function)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'Accept-' + event
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, acceptFunc, name = name)
|
||
|
|
||
|
### FunctionInterval subclass for ignoring events ###
|
||
|
class IgnoreInterval(FunctionInterval):
|
||
|
# Initialization
|
||
|
def __init__(self, dirObj, event, name = None):
|
||
|
"""__init__(dirObj, event, name)
|
||
|
"""
|
||
|
def ignoreFunc(dirObj = dirObj, event = event):
|
||
|
dirObj.ignore(event)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'Ignore-' + event
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, ignoreFunc, name = name)
|
||
|
|
||
|
### Function Interval subclass for adjusting scene graph hierarchy ###
|
||
|
class ParentInterval(FunctionInterval):
|
||
|
# ParentInterval counter
|
||
|
parentIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, parent, name = None):
|
||
|
"""__init__(nodePath, parent, name)
|
||
|
"""
|
||
|
def reparentFunc(nodePath = nodePath, parent = parent):
|
||
|
nodePath.reparentTo(parent)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'ParentInterval-%d' % ParentInterval.parentIntervalNum
|
||
|
ParentInterval.parentIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, reparentFunc, name = name)
|
||
|
|
||
|
### Function Interval subclass for adjusting scene graph hierarchy ###
|
||
|
class WrtParentInterval(FunctionInterval):
|
||
|
# WrtParentInterval counter
|
||
|
wrtParentIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, parent, name = None):
|
||
|
"""__init__(nodePath, parent, name)
|
||
|
"""
|
||
|
def wrtReparentFunc(nodePath = nodePath, parent = parent):
|
||
|
nodePath.wrtReparentTo(parent)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = ('WrtParentInterval-%d' %
|
||
|
WrtParentInterval.wrtParentIntervalNum)
|
||
|
WrtParentInterval.wrtParentIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, wrtReparentFunc, name = name)
|
||
|
|
||
|
### Function Interval subclasses for instantaneous pose changes ###
|
||
|
class PosInterval(FunctionInterval):
|
||
|
# PosInterval counter
|
||
|
posIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, pos, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, pos, duration, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def posFunc(np = nodePath, pos = pos, other = other):
|
||
|
if other:
|
||
|
np.setPos(other, pos)
|
||
|
else:
|
||
|
np.setPos(pos)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'PosInterval-%d' % PosInterval.posIntervalNum
|
||
|
PosInterval.posIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, posFunc, name = name)
|
||
|
|
||
|
class HprInterval(FunctionInterval):
|
||
|
# HprInterval counter
|
||
|
hprIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, hpr, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, hpr, duration, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def hprFunc(np = nodePath, hpr = hpr, other = other):
|
||
|
if other:
|
||
|
np.setHpr(other, hpr)
|
||
|
else:
|
||
|
np.setHpr(hpr)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'HprInterval-%d' % HprInterval.hprIntervalNum
|
||
|
HprInterval.hprIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, hprFunc, name = name)
|
||
|
|
||
|
class ScaleInterval(FunctionInterval):
|
||
|
# ScaleInterval counter
|
||
|
scaleIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, scale, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, scale, duration, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def scaleFunc(np = nodePath, scale = scale, other = other):
|
||
|
if other:
|
||
|
np.setScale(other, scale)
|
||
|
else:
|
||
|
np.setScale(scale)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'ScaleInterval-%d' % ScaleInterval.scaleIntervalNum
|
||
|
ScaleInterval.scaleIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, scaleFunc, name = name)
|
||
|
|
||
|
class PosHprInterval(FunctionInterval):
|
||
|
# PosHprInterval counter
|
||
|
posHprIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, pos, hpr, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, pos, hpr, duration, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def posHprFunc(np = nodePath, pos = pos, hpr = hpr, other = other):
|
||
|
if other:
|
||
|
np.setPosHpr(other, pos, hpr)
|
||
|
else:
|
||
|
np.setPosHpr(pos, hpr)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = 'PosHprInterval-%d' % PosHprInterval.posHprIntervalNum
|
||
|
PosHprInterval.posHprIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, posHprFunc, name = name)
|
||
|
|
||
|
class HprScaleInterval(FunctionInterval):
|
||
|
# HprScaleInterval counter
|
||
|
hprScaleIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, hpr, scale, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, hpr, scale, duration, other, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def hprScaleFunc(np=nodePath, hpr=hpr, scale=scale,
|
||
|
other = other):
|
||
|
if other:
|
||
|
np.setHprScale(other, hpr, scale)
|
||
|
else:
|
||
|
np.setHprScale(hpr, scale)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = ('HprScale-%d' %
|
||
|
HprScaleInterval.hprScaleIntervalNum)
|
||
|
HprScaleInterval.hprScaleIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, hprScaleFunc, name = name)
|
||
|
|
||
|
class PosHprScaleInterval(FunctionInterval):
|
||
|
# PosHprScaleInterval counter
|
||
|
posHprScaleIntervalNum = 1
|
||
|
# Initialization
|
||
|
def __init__(self, nodePath, pos, hpr, scale, duration = 0.0,
|
||
|
name = None, other = None):
|
||
|
"""__init__(nodePath, pos, hpr, scale, duration, other, name)
|
||
|
"""
|
||
|
# Create function
|
||
|
def posHprScaleFunc(np=nodePath, pos=pos, hpr=hpr, scale=scale,
|
||
|
other = other):
|
||
|
if other:
|
||
|
np.setPosHprScale(other, pos, hpr, scale)
|
||
|
else:
|
||
|
np.setPosHprScale(pos, hpr, scale)
|
||
|
# Determine name
|
||
|
if (name == None):
|
||
|
name = ('PosHprScale-%d' %
|
||
|
PosHprScaleInterval.posHprScaleIntervalNum)
|
||
|
PosHprScaleInterval.posHprScaleIntervalNum += 1
|
||
|
# Create function interval
|
||
|
FunctionInterval.__init__(self, posHprScaleFunc, name = name)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class Func(FunctionInterval):
|
||
|
def __init__(self, *args, **kw):
|
||
|
function = args[0]
|
||
|
assert hasattr(function, '__call__')
|
||
|
extraArgs = args[1:]
|
||
|
kw['extraArgs'] = extraArgs
|
||
|
FunctionInterval.__init__(self, function, **kw)
|
||
|
|
||
|
class Wait(WaitInterval):
|
||
|
def __init__(self, duration):
|
||
|
WaitInterval.__init__(self, duration)
|
||
|
|
||
|
"""
|
||
|
SAMPLE CODE
|
||
|
|
||
|
from IntervalGlobal import *
|
||
|
|
||
|
i1 = Func(base.transitions.fadeOut)
|
||
|
i2 = Func(base.transitions.fadeIn)
|
||
|
|
||
|
def caughtIt():
|
||
|
print 'Caught here-is-an-event'
|
||
|
|
||
|
class DummyAcceptor(DirectObject):
|
||
|
pass
|
||
|
|
||
|
da = DummyAcceptor()
|
||
|
i3 = Func(da.accept, 'here-is-an-event', caughtIt)
|
||
|
|
||
|
i4 = Func(messenger.send, 'here-is-an-event')
|
||
|
|
||
|
i5 = Func(da.ignore, 'here-is-an-event')
|
||
|
|
||
|
# Using a function
|
||
|
def printDone():
|
||
|
print 'done'
|
||
|
|
||
|
i6 = Func(printDone)
|
||
|
|
||
|
# Create track
|
||
|
t1 = Sequence([
|
||
|
# Fade out
|
||
|
(0.0, i1),
|
||
|
# Fade in
|
||
|
(2.0, i2),
|
||
|
# Accept event
|
||
|
(4.0, i3),
|
||
|
# Throw it,
|
||
|
(5.0, i4),
|
||
|
# Ignore event
|
||
|
(6.0, i5),
|
||
|
# Throw event again and see if ignore worked
|
||
|
(7.0, i4),
|
||
|
# Print done
|
||
|
(8.0, i6)], name = 'demo')
|
||
|
|
||
|
# Play track
|
||
|
t1.play()
|
||
|
|
||
|
### Specifying interval start times during track construction ###
|
||
|
# Interval start time can be specified relative to three different points:
|
||
|
# PREVIOUS_END
|
||
|
# PREVIOUS_START
|
||
|
# TRACK_START
|
||
|
|
||
|
startTime = 0.0
|
||
|
def printStart():
|
||
|
global startTime
|
||
|
startTime = globalClock.getFrameTime()
|
||
|
print 'Start'
|
||
|
|
||
|
def printPreviousStart():
|
||
|
global startTime
|
||
|
currTime = globalClock.getFrameTime()
|
||
|
print 'PREVIOUS_END %0.2f' % (currTime - startTime)
|
||
|
|
||
|
def printPreviousEnd():
|
||
|
global startTime
|
||
|
currTime = globalClock.getFrameTime()
|
||
|
print 'PREVIOUS_END %0.2f' % (currTime - startTime)
|
||
|
|
||
|
def printTrackStart():
|
||
|
global startTime
|
||
|
currTime = globalClock.getFrameTime()
|
||
|
print 'TRACK_START %0.2f' % (currTime - startTime)
|
||
|
|
||
|
i1 = Func(printStart)
|
||
|
# Just to take time
|
||
|
i2 = LerpPosInterval(camera, 2.0, Point3(0, 10, 5))
|
||
|
# This will be relative to end of camera move
|
||
|
i3 = FunctionInterval(printPreviousEnd)
|
||
|
# Just to take time
|
||
|
i4 = LerpPosInterval(camera, 2.0, Point3(0, 0, 5))
|
||
|
# This will be relative to the start of the camera move
|
||
|
i5 = FunctionInterval(printPreviousStart)
|
||
|
# This will be relative to track start
|
||
|
i6 = FunctionInterval(printTrackStart)
|
||
|
# Create the track, if you don't specify offset type in tuple it defaults to
|
||
|
# relative to TRACK_START (first entry below)
|
||
|
t2 = Track([(0.0, i1), # i1 start at t = 0, duration = 0.0
|
||
|
(1.0, i2, TRACK_START), # i2 start at t = 1, duration = 2.0
|
||
|
(2.0, i3, PREVIOUS_END), # i3 start at t = 5, duration = 0.0
|
||
|
(1.0, i4, PREVIOUS_END), # i4 start at t = 6, duration = 2.0
|
||
|
(3.0, i5, PREVIOUS_START), # i5 start at t = 9, duration = 0.0
|
||
|
(10.0, i6, TRACK_START)], # i6 start at t = 10, duration = 0.0
|
||
|
name = 'startTimeDemo')
|
||
|
|
||
|
t2.play()
|
||
|
|
||
|
|
||
|
smiley = loader.loadModel('models/misc/smiley')
|
||
|
|
||
|
from direct.actor import Actor
|
||
|
donald = Actor.Actor()
|
||
|
donald.loadModel("phase_6/models/char/donald-wheel-1000")
|
||
|
donald.loadAnims({"steer":"phase_6/models/char/donald-wheel-wheel"})
|
||
|
donald.reparentTo(render)
|
||
|
|
||
|
|
||
|
seq = Sequence(Func(donald.setPos, 0, 0, 0),
|
||
|
donald.actorInterval('steer', duration=1.0),
|
||
|
donald.posInterval(1, Point3(0, 0, 1)),
|
||
|
Parallel(donald.actorInterval('steer', duration=1.0),
|
||
|
donald.posInterval(1, Point3(0, 0, 0)),
|
||
|
),
|
||
|
Wait(1.0),
|
||
|
Func(base.toggleWireframe),
|
||
|
Wait(1.0),
|
||
|
Parallel(donald.actorInterval('steer', duration=1.0),
|
||
|
donald.posInterval(1, Point3(0, 0, -1)),
|
||
|
Sequence(donald.hprInterval(1, Vec3(180, 0, 0)),
|
||
|
donald.hprInterval(1, Vec3(0, 0, 0)),
|
||
|
),
|
||
|
),
|
||
|
Func(base.toggleWireframe),
|
||
|
Func(messenger.send, 'hello'),
|
||
|
)
|
||
|
|
||
|
|
||
|
|
||
|
"""
|