*** empty log message ***

This commit is contained in:
Mark Mine 2001-04-05 05:00:05 +00:00
parent b21b19899f
commit f1de09e0bf
8 changed files with 256 additions and 69 deletions

View File

@ -7,6 +7,15 @@ class AnimInterval(Interval):
# Name counter
animNum = 1
# Class methods
# Interval used to play an animation. If loop = 0, animation is
# played only once and the pose of the anim depends on t passed
# into the setT method every frame. If loop = 1, the animation is
# started and plays on its own and stopped when t > duration or
# IVAL_STOP event occurs. If no duration is specified, interval
# duration defaults to be equal to the length of the animation.
# Note: if loop == 0 and duration > anim duration then the animation
# will play once and then nothing will happen for the remainder of the
# interval
def __init__(self, animControl, loop = 0, duration = 0.0, name=None):
"""__init__(name)
"""

View File

@ -18,9 +18,12 @@ class FunctionInterval(Interval):
name = 'FunctionInterval-%d' % FunctionInterval.functionIntervalNum
FunctionInterval.functionIntervalNum += 1
# Initialize superclass
# Set openEnded true if calls after end time cause interval
# function to be called
# Set openEnded true if IVAL_INIT calls after end time cause interval
# function to be called. If false, IVAL_INIT calls have no effect
# Event, Accept, Ignore intervals default to fOpenEnded = 0
# Parent, Pos, Hpr, etc intervals default to fOpenEnded = 1
Interval.__init__(self, name, duration = 0.0, openEnded = openEnded)
def updateFunc(self, t, event = IVAL_NONE):
""" updateFunc(t, event)
Go to time t
@ -44,25 +47,29 @@ class EventInterval(FunctionInterval):
### FunctionInterval subclass for accepting hooks ###
class AcceptInterval(FunctionInterval):
# Initialization
def __init__(self, dirObj, event, function, name):
def __init__(self, dirObj, event, function, name = None):
"""__init__(dirObj, event, function, name)
"""
def acceptFunc(dirObj = dirObj, event = event, function = function):
print "accepting..."
dirObj.accept(event, function)
# Determine name
if (name == None):
name = 'Accept-' + event
# Create function interval
FunctionInterval.__init__(self, acceptFunc, name = name,
openEnded = 0)
### FunctionInterval subclass for throwing events ###
### FunctionInterval subclass for ignoring events ###
class IgnoreInterval(FunctionInterval):
# Initialization
def __init__(self, dirObj, event, name):
def __init__(self, dirObj, event, name = None):
"""__init__(dirObj, event, name)
"""
def ignoreFunc(dirObj = dirObj, event = event):
print "ignoring..."
dirObj.ignore(event)
# Determine name
if (name == None):
name = 'Ignore-' + event
# Create function interval
FunctionInterval.__init__(self, ignoreFunc, name = name,
openEnded = 0)
@ -188,7 +195,7 @@ class PosHprInterval(FunctionInterval):
FunctionInterval.__init__(self, posHprFunc, name = name)
class PosHprScaleInterval(FunctionInterval):
# PosHprInterval counter
# PosHprScaleInterval counter
posHprScaleIntervalNum = 1
# Initialization
def __init__(self, nodePath, pos, hpr, scale, duration = 0.0,
@ -212,19 +219,49 @@ class PosHprScaleInterval(FunctionInterval):
"""
SAMPLE CODE
from IntervalGlobal import *
### Using lambdas and functions ###
# Using a lambda
i1 = FunctionInterval(lambda: base.transitions.fadeOut())
i2 = FunctionInterval(lambda: base.transitions.fadeIn())
# Using a function
def printHello():
print 'hello'
i3 = FunctionInterval(printHello)
def caughtIt():
print 'Caught here-is-an-event'
class DummyAcceptor(DirectObject):
pass
da = DummyAcceptor()
i3 = AcceptInterval(da, 'here-is-an-event', caughtIt)
i4 = EventInterval('here-is-an-event')
i5 = IgnoreInterval(da, 'here-is-an-event')
# Using a function
def printDone():
print 'done'
i6 = FunctionInterval(printDone)
# Create track
t1 = Track([(0.0, i1), (2.0, i2), (4.0, i3)], name = 'demo')
t1 = Track([
# 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()

View File

@ -16,8 +16,7 @@ class Interval(DirectObject):
notify = directNotify.newCategory("Interval")
#notify.setDebug(1)
# special methods
# Class methods
def __init__(self, name, duration, openEnded = 1):
"""__init__(name, duration)
"""
@ -65,9 +64,13 @@ class Interval(DirectObject):
self.prev_t = self.curr_t
def updateFunc(self, t, event = IVAL_NONE):
""" updateFunc(t, event)
"""
# Subclasses define this function
pass
def setTHook(self, t):
# Used by control panel to update scale
pass
def setFinalT(self):
@ -79,7 +82,7 @@ class Interval(DirectObject):
""" play(t0, duration)
"""
# Kill ongoing play task
self.stop()
taskMgr.removeTasksNamed(self.name + '-play')
# Start new one
self.offset = t0
self.startT = self.clock.getFrameTime()
@ -93,12 +96,15 @@ class Interval(DirectObject):
# Otherwise use min of interval duration and offset + play duration
self.endTime = min(self.duration, self.offset + duration)
assert(t0 <= self.endTime)
# Spawn task
taskMgr.spawnMethodNamed(self.__playTask, self.name + '-play')
def stop(self):
""" stop()
"""
# Kill task
taskMgr.removeTasksNamed(self.name + '-play')
# And stop freerunning (e.g. sound and anim) intervals
self.setT(self.curr_t, event = IVAL_STOP)
return self.curr_t
@ -108,6 +114,7 @@ class Interval(DirectObject):
t = self.clock.getFrameTime()
te = self.offset + ((t - self.startT) * self.scale)
if (te < self.endTime):
# If first call, init intervals
if (self.firstTime):
self.setT(te, event = IVAL_INIT)
self.firstTime = 0
@ -127,6 +134,9 @@ class Interval(DirectObject):
return (space + self.name + ' dur: %.2f' % self.duration)
def popupControls(self):
""" popupControls()
Popup control panel for interval.
"""
import fpformat
import string
# I moved this here because Toontown does not ship Tk
@ -146,11 +156,14 @@ class Interval(DirectObject):
# INIT interval
s.setT(es.get(), event = IVAL_INIT)
es.onPress = onPress
# To make sure you stop free running intervals
es.onRelease = lambda s=self: s.stop()
# To update scale and execute intervals with IVAL_INIT
es.onReturnRelease = lambda s=self, es = es: s.setT(es.get(),
event = IVAL_INIT)
es.pack(expand = 1, fill = X)
f = Frame(tl)
# Jump to start and end
def toStart(s=self, es=es):
s.stop()
s.setT(0.0, event = IVAL_INIT)
@ -158,6 +171,7 @@ class Interval(DirectObject):
s.stop()
s.setT(s.getDuration(), event = IVAL_INIT)
jumpToStart = Button(tl, text = '<<', command = toStart)
# Stop/play buttons
stop = Button(tl, text = 'Stop',
command = lambda s=self: s.stop())
play = Button(
@ -169,11 +183,11 @@ class Interval(DirectObject):
stop.pack(side = LEFT, expand = 1, fill = X)
jumpToEnd.pack(side = LEFT, expand = 1, fill = X)
f.pack(expand = 1, fill = X)
# Add hook to update slider on changes in curr_t
# Add function to update slider during setT calls
def update(t,es=es):
es.set(t, fCommand = 0)
self.setTHooks.append(update)
# Clear out hook on destroy
# Clear out function on destroy
def onDestroy(e, s=self, u=update):
if u in s.setTHooks:
s.setTHooks.remove(u)

View File

@ -72,3 +72,102 @@ def handleWaterDone():
print 'water is done'
messenger.accept('water-is-done', 1, handleWaterDone)
### Using lambdas and functions ###
# Using a lambda
i1 = FunctionInterval(lambda: base.transitions.fadeOut())
i2 = FunctionInterval(lambda: base.transitions.fadeIn())
def caughtIt():
print 'Caught here-is-an-event'
class DummyAcceptor(DirectObject):
pass
da = DummyAcceptor()
i3 = AcceptInterval(da, 'here-is-an-event', caughtIt)
i4 = EventInterval('here-is-an-event')
i5 = IgnoreInterval(da, 'here-is-an-event')
# Using a function
def printDone():
print 'done'
i6 = FunctionInterval(printDone)
# Create track
t1 = Track([
# 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')
print(t1)
### 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 = FunctionInterval(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')
print(t2)
# Play tracks
# mtrack.play()
# t1.play()
# t2.play()

View File

@ -9,18 +9,20 @@ class LerpInterval(Interval):
def __init__(self, name, duration, functorFunc, blendType='noBlend'):
"""__init__(name, duration, functorFunc, blendType)
"""
# Record instance variables
self.lerp = None
self.functorFunc = functorFunc
self.blendType = self.getBlend(blendType)
# Initialize superclass
Interval.__init__(self, name, duration)
def updateFunc(self, t, event = IVAL_NONE):
""" updateFunc(t, event)
"""
# First check to see if we need to create the lerp
# Check to see if we need to create the lerp
if (event == IVAL_INIT):
self.lerp = Lerp.Lerp(self.functorFunc(), self.duration,
self.blendType)
# Now evaluate the lerp
# Evaluate the lerp if its been created
if self.lerp:
self.lerp.setT(t)
def getBlend(self, blendType):
@ -51,7 +53,6 @@ class LerpPosInterval(LerpInterval):
def functorFunc(self=self, node=node, pos=pos, startPos=startPos,
other=other):
import PosLerpFunctor
assert(not node.isEmpty())
if (other != None):
# lerp wrt other
@ -227,7 +228,8 @@ class LerpPosHprScaleInterval(LerpInterval):
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
# Class used to execute a function over time. Function can access fromData
# and toData to perform blend
# and toData to perform blend. If fromData and toData not specified, will
# execute the given function passing in values ranging from 0 to 1
class LerpFunctionInterval(Interval):
# Interval counter
lerpFunctionIntervalNum = 1
@ -252,21 +254,24 @@ class LerpFunctionInterval(Interval):
""" updateFunc(t, event)
"""
# Evaluate the function
if (t == self.duration):
if (t >= self.duration):
# Set to end value
self.function(self.toData)
else:
# In the middle of the lerp, compute appropriate value
# In the middle of the lerp, compute appropriate blended value
try:
bt = self.blendType(t/self.duration)
data = (self.fromData * (1 - bt)) + (self.toData * bt)
# Evaluate function
self.function(data)
except ZeroDivisionError:
# Zero duration, just use endpoint
self.function(self.toData)
def getBlend(self, blendType):
"""__getBlend(self, string)
Return the C++ blend class corresponding to blendType string
"""
# Note, this is temporary until blend functions get exposed
import LerpBlendHelpers
def easeIn(t):
x = t*t

View File

@ -4,26 +4,26 @@ from Interval import *
from Track import *
class MultiTrack(Interval):
# Name counter
multiTrackNum = 1
# special methods
# Class methods
def __init__(self, trackList, name=None):
"""__init__(trackList, name)
"""
if (name == None):
n = 'MultiTrack-%d' % MultiTrack.multiTrackNum
MultiTrack.multiTrackNum = MultiTrack.multiTrackNum + 1
else:
n = name
# Record track list
self.tlist = trackList
if (name == None):
name = 'MultiTrack-%d' % MultiTrack.multiTrackNum
MultiTrack.multiTrackNum = MultiTrack.multiTrackNum + 1
# Duration is max of all track durations
duration = self.__computeDuration()
Interval.__init__(self, n, duration)
# Initialize superclass
Interval.__init__(self, name, duration)
# Access track at given index
def __getitem__(self, item):
return self.tlist[item]
def __computeDuration(self):
""" __computeDuration()
Returns the duration of the longest Track
@ -43,11 +43,15 @@ class MultiTrack(Interval):
tEnd = track.getDuration()
# Compare time with track's end times
if (t > tEnd):
# If t > tEnd, only call if just crossing over
# or this is an IVAL_INIT event
if (self.prev_t < tEnd) or (event == IVAL_INIT):
track.setT(t, event)
else:
# Update track
track.setT(t, event)
# Print out representation of MultiTrack
def __repr__(self, indent=0):
""" __repr__(indent)
"""

View File

@ -7,36 +7,43 @@ class SoundInterval(Interval):
# Name counter
soundNum = 1
# Class methods
def __init__(self, sound, loop=0, name=None):
# Create a sound interval
# If loop = 0, sound will play once, duration of the interval
# equals the duration of the sound
# If loop = 1, the sound will loop for the specified duration
# If no duration is specified, sound will loop for the duration
# of the sound, i.e. it will only play once.....usually, there
# seems to be some timing in the audio such that the stop doesn't
# kill the looping sound until the next time around if duration
# of the interval equals duration of the sound
def __init__(self, sound, loop = 0, duration = 0.0, name = None):
"""__init__(sound, loop, name)
"""
# Record instance variables
self.sound = sound
self.loop = loop
self.isPlaying = 0
# If no duration given use sound's duration as interval's duration
if duration == 0.0:
duration = self.sound.length()
# Generate unique name if necessary
if (name == None):
name = 'Sound-%d' % SoundInterval.soundNum
SoundInterval.soundNum += 1
# Calculate duration
duration = self.sound.length()
# Initialize superclass
Interval.__init__(self, name, duration)
def updateFunc(self, t, event = IVAL_NONE):
""" updateFunc(t, event)
Go to time t
"""
if (t == self.duration) or (event == IVAL_STOP):
# Stop sound if necessary
if (self.isPlaying == 1):
self.isPlaying = 0
AudioManager.stop(self.sound)
# Update sound based on current time
if (t >= self.getDuration()) or (event == IVAL_STOP):
# If end of sound reached or stop event received, stop sound
AudioManager.stop(self.sound)
elif (event == IVAL_INIT):
# Set flag
self.isPlaying = 1
# If its within a 20th of a second of the start,
# IVAL_INIT event, start new sound
# If its within a 10th of a second of the start,
# start at the beginning
if (t < 0.05):
if (t < 0.1):
t = 0.0
# Start sound
AudioManager.play(self.sound, t)

View File

@ -1,7 +1,6 @@
"""Track module: contains the Track class"""
from Interval import *
import types
PREVIOUS_END = 1
@ -33,9 +32,12 @@ class Track(Interval):
# Initialize superclass
Interval.__init__(self, name, duration)
# Access interval at given index
def __getitem__(self, item):
return self.ilist[item]
# Create a list of this track's intervals, recording time
# and time type (relative to track start, previous start, previous end
def __buildIlist(self, intervalList):
self.ilist = []
for i in intervalList:
@ -43,39 +45,42 @@ class Track(Interval):
self.ilist.append([i, 0.0, PREVIOUS_END, 0.0, 0.0])
elif (isinstance(i, types.ListType) or
isinstance(i, types.TupleType)):
t0 = i[0]
itime = i[0]
ival = i[1]
try:
type = i[2]
except IndexError:
type = TRACK_START
self.ilist.append([ival, t0, type, 0.0, 0.0])
self.ilist.append([ival, itime, type, 0.0, 0.0])
else:
print 'Track.__buildIlist: Invalid intervallist entry'
# Compute duration of the track and precompute start and end time of
# each interval
def __computeDuration(self):
""" __computeDuration()
"""
duration = 0.0
prev = None
for idata in self.ilist:
ival = idata[IDATA_IVAL]
t0 = idata[IDATA_TIME]
type = idata[IDATA_TYPE]
assert(t0 >= 0.0)
ival = idata[IDATA_IVAL]
itime = idata[IDATA_TIME]
type = idata[IDATA_TYPE]
assert(itime >= 0.0)
# Compute fill time, time between end of last interval and
# start of this one
fillTime = t0
# start of this one. Depend on interval type
fillTime = itime
if (type == PREVIOUS_END):
pass
elif (type == PREVIOUS_START):
if (prev != None):
fillTime = t0 - prev.getDuration()
fillTime = itime - prev.getDuration()
elif (type == TRACK_START):
fillTime = t0 - duration
fillTime = itime - duration
else:
Interval.notify.error(
'Track.__computeDuration(): unknown type: %d' % type)
# Check for overlap
if (fillTime < 0.0):
Interval.notify.error(
'Track.__computeDuration(): overlap detected')
@ -83,22 +88,25 @@ class Track(Interval):
idata[IDATA_START] = duration + fillTime
# Compute end time of interval
idata[IDATA_END] = idata[IDATA_START] + ival.getDuration()
# Keep track of current duration
# Keep track of cumulative duration
duration = idata[IDATA_END]
prev = ival
return duration
def setIntervalStartTime(self, name, t0, type=TRACK_START):
""" setIntervalStartTime(name, t0, type)
def setIntervalStartTime(self, name, itime, type=TRACK_START):
""" setIntervalStartTime(name, itime, type)
"""
found = 0
# Check for interval in current interval list
for idata in self.ilist:
# If found, update time and type
if (idata[IDATA_IVAL].getName() == name):
idata[IDATA_TIME] = t0
idata[IDATA_TIME] = itime
idata[IDATA_TYPE] = type
found = 1
break
if (found):
# And recompute duration
self.duration = self.__computeDuration()
else:
Interval.notify.warning(
@ -107,6 +115,7 @@ class Track(Interval):
def getIntervalStartTime(self, name):
""" getIntervalStartTime(name)
"""
# Search for interval of given name
for idata in self.ilist:
if (idata[IDATA_IVAL].getName() == name):
return idata[IDATA_START]
@ -117,6 +126,7 @@ class Track(Interval):
def __getIntervalStartTime(self, interval):
""" __getIntervalStartTime(interval)
"""
# Search for given interval
for idata in self.ilist:
if (idata[IDATA_IVAL] == interval):
return idata[IDATA_START]
@ -127,6 +137,7 @@ class Track(Interval):
def getIntervalEndTime(self, name):
""" getIntervalEndTime(name)
"""
# Search for interval of given name
for idata in self.ilist:
if (idata[IDATA_IVAL].getName() == name):
return idata[IDATA_END]
@ -152,8 +163,7 @@ class Track(Interval):
currentInterval = None
# First entry, re-init instance variables
if (event == IVAL_INIT):
# Initialize prev_t to max t of track
#self.prev_t = self.getDuration()
# Initialize prev_t to 0.0
self.prev_t = 0.0
# Clear record of currentInterval
self.currentInterval = None
@ -166,7 +176,7 @@ class Track(Interval):
# start of an interval ((prev_t > tStart) and (t < tStart))
# then execute that interval at its start value
for ival, itime, itype, tStart, tEnd in self.ilist:
# Compare time with ival's start/end times
# Compare time with each ival's start/end times
if (t < tStart):
if (self.prev_t > tStart) and (event != IVAL_STOP):
# We just crossed the start of this interval
@ -200,11 +210,13 @@ class Track(Interval):
# Record current interval (may be None)
self.currentInterval = currentInterval
# Create a printable representation of the track
def __repr__(self, indent=0):
""" __repr__(indent)
"""
str = Interval.__repr__(self, indent) + '\n'
for idata in self.ilist:
for idata in self.ilist:
# Tack on start and end time for this interval
str = (str + idata[IDATA_IVAL].__repr__(indent+1) +
(' start: %0.2f end: %0.2f' %
(idata[IDATA_START], idata[IDATA_END])) + '\n'