new C++-based intervals

This commit is contained in:
David Rose
2002-08-29 16:45:26 +00:00
parent 205ad5429f
commit 8143fa084c
33 changed files with 3804 additions and 740 deletions

View File

@@ -8,7 +8,7 @@
#define BUILDING_DLL BUILDING_DIRECT
#define COMPONENT_LIBS \
directbase dcparser showbase deadrec directd
directbase dcparser showbase deadrec directd interval
#define OTHER_LIBS panda pandaexpress dtoolconfig dtool

View File

@@ -122,7 +122,7 @@ class ActorInterval(Interval.Interval):
self.goToT(t)
class LerpAnimInterval(Interval.Interval):
class LerpAnimInterval(CLerpAnimEffectInterval):
# Blends between two anims. Start both anims first (or use
# parallel ActorIntervals), then invoke LerpAnimInterval to
# smoothly blend the control effect from the first to the second.
@@ -131,58 +131,25 @@ class LerpAnimInterval(Interval.Interval):
def __init__(self, actor, duration, startAnim, endAnim,
startWeight = 0.0, endWeight = 1.0,
blendType = 'noBlend', name = None):
""" __init__(actor, duration, pos, startPos, other, blendType, name)
"""
# Generate unique name if necessary
if (name == None):
name = 'LerpAnimInterval-%d' % LerpAnimInterval.lerpAnimNum
LerpAnimInterval.lerpAnimNum += 1
# Record class specific variables
self.actor = actor
self.startAnim = startAnim
self.endAnim = endAnim
self.startWeight = startWeight
self.deltaWeight = endWeight - startWeight
self.blendType = self.getBlend(blendType)
blendType = self.stringBlendType(blendType)
assert(blendType != self.BTInvalid)
# Initialize superclass
Interval.Interval.__init__(self, name, duration)
CLerpAnimEffectInterval.__init__(self, name, duration, blendType)
def updateFunc(self, t, event=Interval.IVAL_NONE):
""" updateFunc(t, event)
Go to time t
"""
if (self.actor.isEmpty()):
self.notify.warning('updateFunc() - %s empty actor!' % self.name)
return
# First, normalize t into the range 0 .. 1, and apply the blendType.
t = self.blendType(float(t) / self.duration)
# Then compute the current weight based on the time elapsed so far.
w = self.startWeight + t * self.deltaWeight
# Apply that weight to the two anims.
if self.startAnim != None:
self.actor.setControlEffect(self.startAnim, 1.0 - w)
if self.endAnim != None:
self.actor.setControlEffect(self.endAnim, w)
def getBlend(self, blendType):
"""__getBlend(self, string)
Return the C++ blend class corresponding to blendType string
"""
if (blendType == "easeIn"):
return LerpBlendHelpers.easeIn
elif (blendType == "easeOut"):
return LerpBlendHelpers.easeOut
elif (blendType == "easeInOut"):
return LerpBlendHelpers.easeInOut
elif (blendType == "noBlend"):
return LerpBlendHelpers.noBlend
else:
raise Exception(
'Error: LerpAnimInterval.getBlend: Unknown blend type')
if startAnim != None:
controls = actor.getAnimControls(startAnim)
for control in controls:
self.addControl(control, startAnim,
1.0 - startWeight, 1.0 - endWeight)
if endAnim != None:
controls = actor.getAnimControls(endAnim)
for control in controls:
self.addControl(control, endAnim,
startWeight, endWeight)

View File

@@ -27,7 +27,7 @@ class FunctionInterval(Interval.Interval):
self.function = function
# Create a unique name for the interval if necessary
if (name == None):
name = 'FunctionInterval-%d' % FunctionInterval.functionIntervalNum
name = 'FunctionInterval-%s-%d' % (function.__name__, FunctionInterval.functionIntervalNum)
FunctionInterval.functionIntervalNum += 1
assert(isinstance(name, types.StringType))
# Record any arguments

View File

@@ -5,9 +5,9 @@ from PandaModules import *
import Task
# Interval events
IVAL_NONE = 0
IVAL_INIT = 1
IVAL_DONE = 2
IVAL_NONE = CInterval.ETStep
IVAL_INIT = CInterval.ETInitialize
IVAL_DONE = CInterval.ETFinalize
class Interval(DirectObject):
"""Interval class: Base class for timeline functionality"""
@@ -75,7 +75,7 @@ class Interval(DirectObject):
def setFinalT(self):
""" setFinalT()
"""
self.setT(self.getDuration(), event=IVAL_DONE)
self.setT(self.getDuration(), IVAL_DONE)
def play(self, t0=0.0, duration=0.0, scale=1.0):
""" play(t0, duration)
@@ -133,7 +133,7 @@ class Interval(DirectObject):
if (te < self.endTime):
if (self.firstTime):
# If first call, init intervals
self.setT(te, event = IVAL_INIT)
self.setT(te, IVAL_INIT)
self.firstTime = 0
else:
self.setT(te)
@@ -142,7 +142,7 @@ class Interval(DirectObject):
te = self.endTime
if (self.firstTime):
# If first call, init intervals
self.setT(te, event = IVAL_INIT)
self.setT(te, IVAL_INIT)
self.firstTime = 0
else:
self.setT(te, IVAL_DONE)
@@ -181,23 +181,23 @@ class Interval(DirectObject):
# Kill playback task
taskMgr.remove(s.name + '-play')
# INIT interval
s.setT(es.get(), event = IVAL_INIT)
s.setT(es.get(), 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
def onReturn(s = self, es = es):
s.setT(es.get(), event = IVAL_INIT)
s.setT(es.get(), IVAL_INIT)
s.stop()
es.onReturnRelease = onReturn
es.pack(expand = 1, fill = X)
bf = Frame(outerFrame)
# Jump to start and end
def toStart(s=self, es=es):
s.setT(0.0, event = IVAL_INIT)
s.setT(0.0, IVAL_INIT)
s.stop()
def toEnd(s=self):
s.setT(s.getDuration(), event = IVAL_INIT)
s.setT(s.getDuration(), IVAL_INIT)
s.stop()
jumpToStart = Button(bf, text = '<<', command = toStart)
# Stop/play buttons

View File

@@ -9,6 +9,4 @@ from MopathInterval import *
from ParticleInterval import *
from SoundInterval import *
from WaitInterval import *
from Track import *
from MultiTrack import *
from MetaInterval import *

View File

@@ -5,6 +5,262 @@ from DirectNotifyGlobal import *
import Interval
import LerpBlendHelpers
#
# Most of the intervals defined in this module--the group up here at
# the front of the file--are now derived from a CInterval instead of
# an Interval, so they can run in the low-level C++ code at high
# performance.
#
class LerpNodePathInterval(CLerpNodePathInterval):
# This is the base class for all of the lerps, defined below, that
# affect a property on a NodePath, like pos or hpr.
lerpNodePathNum = 1
def __init__(self, name, duration, blendType, node, other):
if name == None:
name = '%s-%d' % (self.__class__.__name__, self.lerpNodePathNum)
LerpNodePathInterval.lerpNodePathNum += 1
blendType = self.stringBlendType(blendType)
assert(blendType != self.BTInvalid)
if other == None:
other = NodePath()
CLerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
def anyCallable(self, *params):
# Returns true if any of the parameters listed is a callable
# functor, false if none of them are. This is used by derived
# classes to determine if a functor was passed in for a
# parameter.
for param in params:
if callable(param):
return 1
return 0
def setupParam(self, func, param):
# Stores the indicated parameter by passing it to the given
# function (probably a C++ setter function). If the param is
# a callable functor, calls it; otherwise, uses the param
# directly.
if param != None:
if callable(param):
func(param())
else:
func(param)
#####################################################################
##
## It is legal to pass in a functor for the any of the pos, hpr,
## or scale parameters in the intervals below. These will be
## evaluated at the time the interval starts in order to determine
## the actual final position. However, doing so forces the entire
## LerpInterval to be executed up in Python, instead of down in the
## low-level C++ code, at a significant performance cost.
##
#####################################################################
class LerpPosInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, startPos = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(pos, startPos):
self.endPos = pos
self.startPos = startPos
self.inPython = 1
else:
self.setEndPos(pos)
if startPos != None:
self.setStartPos(startPos)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndPos, self.endPos)
self.setupParam(self.setStartPos, self.startPos)
LerpNodePathInterval.setT(self, t, event)
class LerpHprInterval(LerpNodePathInterval):
def __init__(self, node, duration, hpr, startHpr = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(hpr, startHpr):
self.endHpr = hpr
self.startHpr = startHpr
self.inPython = 1
else:
self.setEndHpr(hpr)
if startHpr != None:
self.setStartHpr(startHpr)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndHpr, self.endHpr)
self.setupParam(self.setStartHpr, self.startHpr)
LerpNodePathInterval.setT(self, t, event)
class LerpScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, scale, startScale = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(scale, startScale):
self.endScale = scale
self.startScale = startScale
self.inPython = 1
else:
self.setEndScale(scale)
if startScale != None:
self.setStartScale(startScale)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndScale, self.endScale)
self.setupParam(self.setStartScale, self.startScale)
LerpNodePathInterval.setT(self, t, event)
class LerpPosHprInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, hpr,
startPos = None, startHpr = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(pos, startPos, hpr, startHpr):
self.endPos = pos
self.startPos = startPos
self.endHpr = hpr
self.startHpr = startHpr
self.inPython = 1
else:
self.setEndPos(pos)
if startPos != None:
self.setStartPos(startPos)
self.setEndHpr(hpr)
if startHpr != None:
self.setStartHpr(startHpr)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndPos, self.endPos)
self.setupParam(self.setStartPos, self.startPos)
self.setupParam(self.setEndHpr, self.endHpr)
self.setupParam(self.setStartHpr, self.startHpr)
LerpNodePathInterval.setT(self, t, event)
class LerpHprScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, hpr, scale,
startHpr = None, startScale = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(hpr, startHpr, scale, startScale):
self.endHpr = hpr
self.startHpr = startHpr
self.endScale = scale
self.startScale = startScale
self.inPython = 1
else:
self.setEndHpr(hpr)
if startHpr != None:
self.setStartHpr(startHpr)
self.setEndScale(scale)
if startScale != None:
self.setStartScale(startScale)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndHpr, self.endHpr)
self.setupParam(self.setStartHpr, self.startHpr)
self.setupParam(self.setEndScale, self.endScale)
self.setupParam(self.setStartScale, self.startScale)
LerpNodePathInterval.setT(self, t, event)
class LerpPosHprScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, hpr, scale,
startPos = None, startHpr = None, startScale = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
# Check for functors in the input parameters.
if self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale):
self.endPos = pos
self.startPos = startPos
self.endHpr = hpr
self.startHpr = startHpr
self.endScale = scale
self.startScale = startScale
self.inPython = 1
else:
self.setEndPos(pos)
if startPos != None:
self.setStartPos(startPos)
self.setEndHpr(hpr)
if startHpr != None:
self.setStartHpr(startHpr)
self.setEndScale(scale)
if startScale != None:
self.setStartScale(startScale)
def setT(self, t, event):
# This function is only used if Python functors were passed in
# for some of the input parameters.
if event == Interval.IVAL_INIT:
self.setupParam(self.setEndPos, self.endPos)
self.setupParam(self.setStartPos, self.startPos)
self.setupParam(self.setEndHpr, self.endHpr)
self.setupParam(self.setStartHpr, self.startHpr)
self.setupParam(self.setEndScale, self.endScale)
self.setupParam(self.setStartScale, self.startScale)
LerpNodePathInterval.setT(self, t, event)
class LerpColorScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, colorScale, startColorScale = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
self.setEndColorScale(colorScale)
if startColorScale != None:
self.setStartColorScale(startColorScale)
class LerpColorInterval(LerpNodePathInterval):
def __init__(self, node, duration, color, startColor = None,
other = None, blendType = 'noBlend', name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
node, other)
self.setEndColor(color)
if startColor != None:
self.setStartColor(startColor)
#
# The remaining intervals defined in this module are the old-school
# Python-based intervals.
#
class LerpInterval(Interval.Interval):
# create LerpInterval DirectNotify category
notify = directNotify.newCategory('LerpInterval')
@@ -51,342 +307,6 @@ class LerpInterval(Interval.Interval):
raise Exception(
'Error: LerpInterval.__getBlend: Unknown blend type')
class LerpPosInterval(LerpInterval):
# Name counter
lerpPosNum = 1
# Class methods
def __init__(self, node, duration, pos, startPos=None,
other=None, blendType='noBlend', name=None):
""" __init__(node, duration, pos, startPos, other, blendType, name)
"""
def functorFunc(node=node, pos=pos, startPos=startPos,
other=other):
assert(not node.isEmpty())
if callable(pos):
# This may be a thunk that returns a point.
pos = pos()
# Make a our own copy of the parameters:
if (pos != None): pos=Point3(pos)
if (startPos != None): startPos=Point3(startPos)
if (other != None):
# lerp wrt other
if (startPos == None):
startPos = node.getPos(other)
functor = PosLerpFunctor(node, startPos, pos, other)
else:
if (startPos == None):
startPos = node.getPos()
functor = PosLerpFunctor(node, startPos, pos)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpPosInterval-%d' % LerpPosInterval.lerpPosNum
LerpPosInterval.lerpPosNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpHprInterval(LerpInterval):
# Name counter
lerpHprNum = 1
# Class methods
def __init__(self, node, duration, hpr, startHpr=None,
other=None, blendType='noBlend', name=None):
""" __init__(node, duration, hpr, startHpr, other, blendType, name)
"""
def functorFunc(node=node, hpr=hpr, startHpr=startHpr,
other=other):
assert(not node.isEmpty())
if callable(hpr):
# This may be a thunk that returns a point.
hpr = hpr()
# Make a our own copy of the parameters:
if (hpr != None): hpr=VBase3(hpr)
if (startHpr != None): startHpr=VBase3(startHpr)
if (other != None):
# lerp wrt other
if (startHpr == None):
startHpr = VBase3(node.getHpr(other))
functor = HprLerpFunctor(node, startHpr, hpr, other)
else:
if (startHpr == None):
startHpr = node.getHpr()
functor = HprLerpFunctor(node, startHpr, hpr)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpHprInterval-%d' % LerpHprInterval.lerpHprNum
LerpHprInterval.lerpHprNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpScaleInterval(LerpInterval):
# Interval counter
lerpScaleNum = 1
# Class methods
def __init__(self, node, duration, scale, startScale=None,
other=None, blendType='noBlend', name=None):
""" __init__(node, duration, scale, startScale, other, blendType, name)
"""
def functorFunc(node=node, scale=scale,
startScale=startScale, other=other):
assert(not node.isEmpty())
if callable(scale):
# This may be a thunk that returns a point.
scale = scale()
# Make a our own copy of the parameters:
if (scale != None): scale=VBase3(scale)
if (startScale != None): startScale=VBase3(startScale)
if (other != None):
# lerp wrt other
if (startScale == None):
startScale = node.getScale(other)
functor = ScaleLerpFunctor(node, startScale, scale, other)
else:
if (startScale == None):
startScale = node.getScale()
functor = ScaleLerpFunctor(node, startScale, scale)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpScaleInterval-%d' % LerpScaleInterval.lerpScaleNum
LerpScaleInterval.lerpScaleNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpPosHprInterval(LerpInterval):
# Interval counter
lerpPosHprNum = 1
def __init__(self, node, duration, pos, hpr, startPos=None,
startHpr=None, other=None, blendType='noBlend', name=None):
""" __init__(node, duration, pos, hpr, startPos, startHpr,
other, blendType, name)
"""
def functorFunc(node=node, pos=pos, hpr=hpr,
startPos=startPos, startHpr=startHpr, other=other):
assert(not node.isEmpty())
if callable(pos):
# This may be a thunk that returns a point.
pos = pos()
if callable(hpr):
# This may be a thunk that returns a point.
hpr = hpr()
# Make a our own copy of the parameters:
if (pos != None): pos=Point3(pos)
if (hpr != None): hpr=VBase3(hpr)
if (startPos != None): startPos=Point3(startPos)
if (startHpr != None): startHpr=VBase3(startHpr)
if (other != None):
# lerp wrt other
if (startPos == None):
startPos = node.getPos(other)
if (startHpr == None):
startHpr = node.getHpr(other)
functor = PosHprLerpFunctor(
node, startPos, pos,
startHpr, hpr, other)
else:
if (startPos == None):
startPos = node.getPos()
if (startHpr == None):
startHpr = node.getHpr()
functor = PosHprLerpFunctor(
node, startPos, pos,
startHpr, hpr)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpPosHpr-%d' % LerpPosHprInterval.lerpPosHprNum
LerpPosHprInterval.lerpPosHprNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpHprScaleInterval(LerpInterval):
# Interval counter
lerpHprScaleNum = 1
# Class methods
def __init__(self, node, duration, hpr, scale,
startHpr=None, startScale=None,
other=None, blendType='noBlend', name=None):
""" __init__(node, duration, hpr, scale,
startHpr, startScale,
other, blendType, name)
"""
def functorFunc(node=node, hpr=hpr, scale=scale,
startHpr=startHpr,
startScale=startScale, other=other):
assert(not node.isEmpty())
if callable(hpr):
# This may be a thunk that returns a point.
hpr = hpr()
if callable(scale):
# This may be a thunk that returns a point.
scale = scale()
# Make a our own copy of the parameters:
if (hpr != None): hpr=VBase3(hpr)
if (scale != None): scale=VBase3(scale)
if (startHpr != None): startHpr=VBase3(startHpr)
if (startScale != None): startScale=VBase3(startScale)
if (other != None):
# lerp wrt other
if (startHpr == None):
startHpr = node.getHpr(other)
if (startScale == None):
startScale = node.getScale(other)
functor = HprScaleLerpFunctor(
node, startHpr, hpr,
startScale, scale, other)
else:
if (startHpr == None):
startHpr = node.getHpr()
if (startScale == None):
startScale = node.getScale()
functor = HprScaleLerpFunctor(
node, startHpr, hpr, startScale, scale)
return functor
# Generate unique name if necessary
if (name == None):
name = ('LerpHprScale-%d' %
LerpHprScaleInterval.lerpHprScaleNum)
LerpHprScaleInterval.lerpHprScaleNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpPosHprScaleInterval(LerpInterval):
# Interval counter
lerpPosHprScaleNum = 1
# Class methods
def __init__(self, node, duration, pos, hpr, scale,
startPos=None, startHpr=None, startScale=None,
other=None, blendType='noBlend', name=None):
""" __init__(node, duration, pos, hpr, scale,
startPos, startHpr, startScale,
other, blendType, name)
"""
def functorFunc(node=node, pos=pos, hpr=hpr, scale=scale,
startPos=startPos, startHpr=startHpr,
startScale=startScale, other=other):
assert(not node.isEmpty())
if callable(pos):
# This may be a thunk that returns a point.
pos = pos()
if callable(hpr):
# This may be a thunk that returns a point.
hpr = hpr()
if callable(scale):
# This may be a thunk that returns a point.
scale = scale()
# Make a our own copy of the parameters:
if (pos != None): pos=Point3(pos)
if (hpr != None): hpr=VBase3(hpr)
if (scale != None): scale=VBase3(scale)
if (startPos != None): startPos=Point3(startPos)
if (startHpr != None): startHpr=VBase3(startHpr)
if (startScale != None): startScale=VBase3(startScale)
if (other != None):
# lerp wrt other
if (startPos == None):
startPos = node.getPos(other)
if (startHpr == None):
startHpr = node.getHpr(other)
if (startScale == None):
startScale = node.getScale(other)
functor = PosHprScaleLerpFunctor(
node, startPos, pos, startHpr, hpr,
startScale, scale, other)
else:
if (startPos == None):
startPos = node.getPos()
if (startHpr == None):
startHpr = node.getHpr()
if (startScale == None):
startScale = node.getScale()
functor = PosHprScaleLerpFunctor(
node, startPos, pos, startHpr, hpr, startScale, scale)
return functor
# Generate unique name if necessary
if (name == None):
name = ('LerpPosHprScale-%d' %
LerpPosHprScaleInterval.lerpPosHprScaleNum)
LerpPosHprScaleInterval.lerpPosHprScaleNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpColorScaleInterval(LerpInterval):
# Name counter
lerpColorScaleNum = 1
# Class methods
def __init__(self, node, duration, startColor, endColor,
other=None, blendType='noBlend', name=None):
def functorFunc(node=node, startColor=startColor, endColor=endColor, other=other):
assert(not node.isEmpty())
if callable(endColor):
# This may be a thunk that returns a point.
endColor = endColor()
if callable(startColor):
# This may be a thunk that returns a point.
startColor = startColor()
# Make a our own copy of the parameters:
if (startColor != None): startColor=VBase4(startColor)
if (endColor != None): endColor=VBase4(endColor)
if (other != None):
functor = ColorScaleLerpFunctor(node, startColor, endColor, other)
else:
functor = ColorScaleLerpFunctor(node, startColor, endColor)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpColorScaleInterval-%d' % LerpColorScaleInterval.lerpColorScaleNum
LerpColorScaleInterval.lerpColorScaleNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpColorInterval(LerpInterval):
# Name counter
lerpColorNum = 1
# Class methods
def __init__(self, node, duration, startColor, endColor,
other=None, blendType='noBlend', name=None):
def functorFunc(node=node, startColor=startColor,
endColor=endColor, other=other):
assert(not node.isEmpty())
if callable(endColor):
# This may be a thunk that returns a point.
endColor = endColor()
if callable(startColor):
# This may be a thunk that returns a point.
startColor = startColor()
# Make a our own copy of the parameters:
if (startColor != None): startColor=VBase4(startColor)
if (endColor != None): endColor=VBase4(endColor)
if (other != None):
functor = ColorLerpFunctor(node, startColor, endColor, other)
else:
functor = ColorLerpFunctor(node, startColor, endColor)
return functor
# Generate unique name if necessary
if (name == None):
name = 'LerpColorInterval-%d' % LerpColorInterval.lerpColorNum
LerpColorInterval.lerpColorNum += 1
# Initialize superclass
LerpInterval.__init__(self, name, duration, functorFunc, blendType)
class LerpFunctionInterval(Interval.Interval):
"""

View File

@@ -1,74 +0,0 @@
"""MultiTrack module: contains the MultiTrack class"""
import Interval
class MultiTrack(Interval.Interval):
# Name counter
multiTrackNum = 1
# Class methods
def __init__(self, trackList, name=None):
"""__init__(trackList, name)
"""
# Record track list
self.tlist = trackList
# Generate name if necessary
if (name == None):
name = 'MultiTrack-%d' % MultiTrack.multiTrackNum
MultiTrack.multiTrackNum = MultiTrack.multiTrackNum + 1
# Duration is max of all track durations
duration = self.__computeDuration()
# Initialize superclass
Interval.Interval.__init__(self, name, duration)
# Update stopEventList after initialization
# It is the union of the stopEventLists of all tracks in the MultiTrack
for t in self.tlist:
self.stopEventList = self.stopEventList + t.stopEventList
# Access track at given index
def __getitem__(self, item):
return self.tlist[item]
def __computeDuration(self):
""" __computeDuration()
Returns the duration of the longest Track
"""
duration = 0.0
for t in self.tlist:
dur = t.getDuration()
if (dur > duration):
duration = dur
return duration
def updateFunc(self, t, event = Interval.IVAL_NONE):
""" updateFunc(t, event)
Go to time t
"""
for track in self.tlist:
# We used to try to be smart about calling this only in
# certain cases, but in fact we just called it in every
# case anyway, so might as well eliminate all of the
# comparisons.
track.setT(t, event)
# Print out representation of MultiTrack
def __repr__(self, indent=0):
""" __repr__(indent)
"""
str = Interval.Interval.__repr__(self, indent) + '\n'
for t in self.tlist:
str = str + t.__repr__(indent+1)
return str
class Parallel(MultiTrack):
def __init__(self, *tracks, **kw):
MultiTrack.__init__(self, tracks, **kw)

View File

@@ -0,0 +1,20 @@
#begin lib_target
#define TARGET interval
#define LOCAL_LIBS \
directbase
#define OTHER_LIBS \
pgraph:c putil:c panda:m express:c pandaexpress:m dtoolconfig dtool
#define SOURCES \
config_interval.cxx config_interval.h \
cInterval.cxx cInterval.I cInterval.h \
cLerpInterval.cxx cLerpInterval.I cLerpInterval.h \
cLerpNodePathInterval.cxx cLerpNodePathInterval.I cLerpNodePathInterval.h \
cLerpAnimEffectInterval.cxx cLerpAnimEffectInterval.I cLerpAnimEffectInterval.h \
cMetaInterval.cxx cMetaInterval.I cMetaInterval.h \
showInterval.cxx showInterval.I showInterval.h \
hideInterval.cxx hideInterval.I hideInterval.h \
lerp_helpers.h
#define IGATESCAN all
#end lib_target

View File

@@ -1,267 +0,0 @@
"""Track module: contains the Track class"""
import Interval
import types
PREVIOUS_END = 1
PREVIOUS_START = 2
TRACK_START = 3
IDATA_IVAL = 0
IDATA_TIME = 1
IDATA_TYPE = 2
IDATA_START = 3
IDATA_END = 4
class Track(Interval.Interval):
# Name counter
trackNum = 1
# Class methods
def __init__(self, intervalList, name=None):
"""__init__(intervalList, name)
intervalList: <Interval> |
'[' <delay>,
<Interval>
[ , PREVIOUS_END | PREVIOUS_START | TRACK_START ] ']'
"""
# Record instance variables
self.currentInterval = None
# Build ilist (need to do this before computing duration)
self.__buildIlist(intervalList)
# Generate unique name if necessary
if (name == None):
name = 'Track-%d' % Track.trackNum
Track.trackNum = Track.trackNum + 1
# Compute duration
duration = self.__computeDuration()
# Initialize superclass
Interval.Interval.__init__(self, name, duration)
# Update stopEventList
for i in self.ilist:
self.stopEventList = self.stopEventList + i[0].stopEventList
# 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, or previous end)
def __buildIlist(self, intervalList):
self.ilist = []
for i in intervalList:
if isinstance(i, Interval.Interval):
self.ilist.append([i, 0.0, PREVIOUS_END, 0.0, 0.0])
elif (isinstance(i, types.ListType) or
isinstance(i, types.TupleType)):
itime = i[0]
ival = i[1]
try:
type = i[2]
except IndexError:
type = TRACK_START
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]
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. Depend on interval type
fillTime = itime
if (type == PREVIOUS_END):
pass
elif (type == PREVIOUS_START):
if (prev != None):
fillTime = itime - prev.getDuration()
elif (type == TRACK_START):
fillTime = itime - duration
else:
self.notify.error(
'Track.__computeDuration(): unknown type: %d' % type)
# Check for overlap
if (fillTime < 0.0):
self.notify.error(
'Track.__computeDuration(): overlap detected')
# Compute start time of interval
idata[IDATA_START] = duration + fillTime
# Compute end time of interval
idata[IDATA_END] = idata[IDATA_START] + ival.getDuration()
# Keep track of cumulative duration
duration = idata[IDATA_END]
prev = ival
return duration
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] = itime
idata[IDATA_TYPE] = type
found = 1
break
if (found):
# And recompute duration
self.duration = self.__computeDuration()
else:
self.notify.warning(
'Track.setIntervalStartTime(): no Interval named: %s' % name)
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]
self.notify.warning(
'Track.getIntervalStartTime(): no Interval named: %s' % name)
return None
def __getIntervalStartTime(self, interval):
""" __getIntervalStartTime(interval)
"""
# Search for given interval
for idata in self.ilist:
if (idata[IDATA_IVAL] == interval):
return idata[IDATA_START]
self.notify.warning(
'Track.getIntervalStartTime(): Interval not found')
return None
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]
self.notify.warning(
'Track.getIntervalEndTime(): no Interval named: %s' % name)
return None
def updateFunc(self, t, event = Interval.IVAL_NONE):
""" updateFunc(t, event)
Go to time t
"""
# Deterimine which interval, if any to evaluate
if (self.currentInterval != None and
event == Interval.IVAL_NONE and
t > self.currentStart and t < self.currentEnd):
# If nothing interesting happened--we're still somewhere
# within the same interval we were within last time--just
# run that one. Trivial case.
self.currentInterval.setT(t - self.currentStart, event)
elif (t < 0):
# Before start of track, do nothing
pass
else:
# The more sophisticated, look-for-the-proper-interval case.
# Make sure track actually contains some intervals
if not self.ilist:
self.notify.warning(
'Track.updateFunc(): track has no intervals')
return
# Initialize local variables
currentInterval = None
currentStart = 0.0
currentEnd = 0.0
# First entry, re-init instance variables
if (event == Interval.IVAL_INIT):
# Initialize prev_t to 0.0
self.prev_t = 0.0
# Clear record of currentInterval
self.currentInterval = None
# Compare t with start and end of each interval to determine
# which interval(s) to execute.
# If t falls between the start and end of an interval, that
# becomes the current interval. If we've crossed over the end
# of an interval ((prev_t < tEnd) and (t > tEnd)) then execute
# that interval at its final value. If we've crossed over the
# 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 each ival's start/end times
if (t < tStart):
if (event == Interval.IVAL_DONE):
# This should only happen in cases of floating
# point instability where t is very close to
# but less than tStart
ival.setT(ival.getDuration(), event)
elif (self.prev_t > tStart):
# We just crossed the start of this interval
# going backwards (e.g. via the slider)
# Execute this interval at its start time
ival.setT(0.0, event)
# Done checking intervals
break
elif (t >= tStart) and (t <= tEnd):
# Between start/end, record current interval
# Make sure event == Interval.IVAL_INIT if entering new interval
if ((event == Interval.IVAL_NONE) and
((self.prev_t < tStart) or
(ival != self.currentInterval))):
event = Interval.IVAL_INIT
# Evaluate interval at interval relative time
if (event == Interval.IVAL_DONE):
ival.setT(ival.getDuration(), event)
else:
ival.setT(t - tStart, event)
currentInterval = ival
currentStart = tStart
currentEnd = tEnd
elif (t > tEnd):
# Crossing over interval end
if (((event == Interval.IVAL_NONE) or (event == Interval.IVAL_DONE)) and
(self.prev_t < tEnd)):
# We've just crossed the end of this interval,
# execute the interval at its end time
# and flag event as Interval.IVAL_DONE
ival.setT(ival.getDuration(), Interval.IVAL_DONE)
elif ((event == Interval.IVAL_INIT) and ival.getOpenEnded()):
# or its an INIT event after the interval's end
# and the interval is openended,
# then execute the interval at its end time
ival.setT(ival.getDuration(), Interval.IVAL_INIT)
# May not be the last, keep checking other intervals
# Record current interval (may be None)
self.currentInterval = currentInterval
self.currentStart = currentStart
self.currentEnd = currentEnd
# Create a printable representation of the track
def __repr__(self, indent=0):
""" __repr__(indent)
"""
str = Interval.Interval.__repr__(self, indent) + '\n'
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'
)
return str
class Sequence(Track):
def __init__(self, *intervals, **kw):
Track.__init__(self, intervals, **kw)

View File

@@ -0,0 +1,127 @@
// Filename: cInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CInterval::get_name
// Access: Published
// Description: Returns the interval's name.
////////////////////////////////////////////////////////////////////
INLINE const string &CInterval::
get_name() const {
return _name;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::get_duration
// Access: Published
// Description: Returns the duration of the interval in seconds.
////////////////////////////////////////////////////////////////////
INLINE double CInterval::
get_duration() const {
recompute();
return _duration;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::get_open_ended
// Access: Published
// Description: Returns the state of the "open_ended" flag. This is
// primarily intended for instantaneous intervals like
// FunctionIntervals; it indicates true if the interval
// has some lasting effect that should be applied even
// if the interval doesn't get started until after its
// finish time, or false if the interval is a transitive
// thing that doesn't need to be called late.
////////////////////////////////////////////////////////////////////
INLINE bool CInterval::
get_open_ended() const {
return _open_ended;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::set_t
// Access: Published
// Description: Advances the interval. This function is provided
// mainly to provide compatibility with the Python
// Interval class; you should use initialize(), step(),
// and finalize() instead.
////////////////////////////////////////////////////////////////////
INLINE void CInterval::
set_t(double t, CInterval::EventType event) {
switch (event) {
case ET_initialize:
initialize(t);
break;
case ET_instant:
instant();
break;
case ET_step:
step(t);
break;
case ET_finalize:
finalize();
break;
case ET_reverse_initialize:
reverse_initialize(t);
break;
case ET_reverse_instant:
reverse_instant();
break;
case ET_reverse_finalize:
reverse_finalize();
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::get_t
// Access: Published
// Description: Returns the current time of the interval: the last
// value of t passed to initialize(), step(), or
// finalize() (or set_t()).
////////////////////////////////////////////////////////////////////
INLINE double CInterval::
get_t() const {
return _curr_t;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::recompute
// Access: Protected
// Description: Calls do_recompute() if the dirty flag has been set.
////////////////////////////////////////////////////////////////////
INLINE void CInterval::
recompute() const {
if (_dirty) {
((CInterval *)this)->do_recompute();
}
}
INLINE ostream &
operator << (ostream &out, const CInterval &ival) {
ival.output(out);
return out;
}

View File

@@ -0,0 +1,362 @@
// Filename: cInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cInterval.h"
#include "indent.h"
#include "clockObject.h"
TypeHandle CInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CInterval::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CInterval::
CInterval(const string &name, double duration, bool open_ended) :
_curr_t(0.0),
_name(name),
_duration(duration),
_open_ended(open_ended),
_dirty(false)
{
_clock_start = 0.0;
_start_t = 0.0;
_end_t = 0.0;
_start_t_at_start = false;
_end_t_at_end = false;
_play_rate = 1.0;
_loop_count = 0;
_restart = true;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::setup_play
// Access: Published
// Description: Called to prepare the interval for automatic timed
// playback, e.g. via a Python task. The interval will
// be played from start_t to end_t, at a time factor
// specified by play_rate. start_t must always be less
// than end_t (except for the exception for end_t == -1,
// below), but if play_rate is negative the interval
// will be played backwards.
//
// Specify end_t of -1 to play the entire interval from
// start_t.
//
// Call step_play() repeatedly to execute the interval.
////////////////////////////////////////////////////////////////////
void CInterval::
setup_play(double start_t, double end_t, double play_rate) {
nassertv(start_t < end_t || end_t < 0.0);
nassertv(play_rate != 0.0);
double duration = get_duration();
if (start_t < 0.0) {
_start_t = 0.0;
_start_t_at_start = true;
} else if (start_t > duration) {
_start_t = duration;
_start_t_at_start = false;
} else {
_start_t = start_t;
_start_t_at_start = false;
}
if (end_t < 0.0 || end_t >= duration) {
_end_t = duration;
_end_t_at_end = true;
} else {
_end_t = end_t;
_end_t_at_end = false;
}
_clock_start = ClockObject::get_global_clock()->get_frame_time();
_play_rate = play_rate;
_loop_count = 0;
_restart = true;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::step_play
// Access: Published
// Description: Should be called once per frame to execute the
// automatic timed playback begun with setup_play().
// The return value is the number of times the interval
// is about to repeat; stop when this reaches one to
// play the interval through exactly once.
////////////////////////////////////////////////////////////////////
int CInterval::
step_play() {
double now = ClockObject::get_global_clock()->get_frame_time();
if (_play_rate >= 0.0) {
double t = (now - _clock_start) * _play_rate + _start_t;
if (t < _end_t) {
// In the middle of the interval, not a problem.
if (_restart) {
initialize(t);
_restart = false;
} else {
step(t);
}
} else {
// Past the ending point; time to finalize.
if (_end_t_at_end) {
// Only finalize if the playback cycle includes the whole
// interval.
if (_restart) {
if (get_open_ended() || _loop_count != 0) {
instant();
}
} else {
finalize();
_restart = true;
}
} else {
if (_restart) {
initialize(_end_t);
_restart = false;
} else {
step(_end_t);
}
}
// Advance the clock for the next loop cycle. We might have to
// advance multiple times if we skipped several cycles in the past
// frame.
if (_end_t == _start_t) {
// If the interval has no length, we loop exactly once each
// time.
_loop_count++;
} else {
// Otherwise, figure out how many loops we need to skip.
double time_per_loop = (_end_t - _start_t) / _play_rate;
double num_loops = floor((now - _clock_start) / time_per_loop);
_loop_count += (int)num_loops;
_clock_start += num_loops * time_per_loop;
}
}
} else {
// Playing backwards.
double t = (now - _clock_start) * _play_rate + _end_t;
if (t >= _start_t) {
// In the middle of the interval, not a problem.
if (_restart) {
reverse_initialize(t);
_restart = false;
} else {
step(t);
}
} else {
// Past the ending point; time to finalize.
if (_start_t_at_start) {
// Only finalize if the playback cycle includes the whole
// interval.
if (_restart) {
if (get_open_ended() || _loop_count != 0) {
reverse_instant();
}
} else {
reverse_finalize();
_restart = true;
}
} else {
if (_restart) {
reverse_initialize(_start_t);
_restart = false;
} else {
step(_start_t);
}
}
// Advance the clock for the next loop cycle. We might have to
// advance multiple times if we skipped several cycles in the past
// frame.
if (_end_t == _start_t) {
// If the interval has no length, we loop exactly once each
// time.
_loop_count++;
} else {
// Otherwise, figure out how many loops we need to skip.
double time_per_loop = (_end_t - _start_t) / -_play_rate;
double num_loops = floor((now - _clock_start) / time_per_loop);
_loop_count += (int)num_loops;
_clock_start += num_loops * time_per_loop;
}
}
}
return _loop_count;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::initialize
// Access: Published, Virtual
// Description: This replaces the first call to step(), and indicates
// that the interval has just begun. This may be
// overridden by derived classes that need to do some
// explicit initialization on the first call.
////////////////////////////////////////////////////////////////////
void CInterval::
initialize(double t) {
recompute();
step(t);
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::instant
// Access: Published, Virtual
// Description: This is called in lieu of initialize() .. step()
// .. finalize(), when everything is to happen within
// one frame. The interval should initialize itself,
// then leave itself in the final state.
////////////////////////////////////////////////////////////////////
void CInterval::
instant() {
recompute();
step(get_duration());
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::step
// Access: Published, Virtual
// Description: Advances the time on the interval. The time may
// either increase (the normal case) or decrease
// (e.g. if the interval is being played by a slider).
////////////////////////////////////////////////////////////////////
void CInterval::
step(double t) {
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::finalize
// Access: Published, Virtual
// Description: This is called to stop an interval, forcing it to
// whatever state it would be after it played all the
// way through. It's generally invoked by
// set_final_t().
////////////////////////////////////////////////////////////////////
void CInterval::
finalize() {
step(get_duration());
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::reverse_initialize
// Access: Published, Virtual
// Description: Similar to initialize(), but this is called when the
// interval is being played backwards; it indicates that
// the interval should start at the finishing state and
// undo any intervening intervals.
////////////////////////////////////////////////////////////////////
void CInterval::
reverse_initialize(double t) {
recompute();
step(t);
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::reverse_instant
// Access: Published, Virtual
// Description: This is called in lieu of reverse_initialize()
// .. step() .. reverse_finalize(), when everything is
// to happen within one frame. The interval should
// initialize itself, then leave itself in the initial
// state.
////////////////////////////////////////////////////////////////////
void CInterval::
reverse_instant() {
recompute();
step(0.0);
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::reverse_finalize
// Access: Published, Virtual
// Description: Called generally following a reverse_initialize(),
// this indicates the interval should set itself to the
// initial state.
////////////////////////////////////////////////////////////////////
void CInterval::
reverse_finalize() {
step(0.0);
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::output
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CInterval::
output(ostream &out) const {
out << get_name();
if (get_duration() != 0.0) {
out << " dur " << get_duration();
}
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::write
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CInterval::
write(ostream &out, int indent_level) const {
indent(out, indent_level) << *this << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::mark_dirty
// Access: Public
// Description: Called by a derived class to indicate the interval has
// been changed internally and must be recomputed before
// its duration may be returned.
////////////////////////////////////////////////////////////////////
void CInterval::
mark_dirty() {
if (!_dirty) {
_dirty = true;
Parents::iterator pi;
for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
(*pi)->mark_dirty();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: CInterval::do_recompute
// Access: Protected, Virtual
// Description: Does whatever processing is necessary to recompute
// the interval after a call to mark_dirty() has
// indicated a recomputation is necessary.
////////////////////////////////////////////////////////////////////
void CInterval::
do_recompute() {
_dirty = false;
}

View File

@@ -0,0 +1,135 @@
// Filename: cInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CINTERVAL_H
#define CINTERVAL_H
#include "directbase.h"
#include "typedReferenceCount.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : CInterval
// Description : The base class for timeline components. A CInterval
// represents a single action, event, or collection of
// nested intervals that will be performed at some
// specific time or over a period of time.
//
// This is essentially similar to the Python "Interval"
// class, but it is implemented in C++ (hence the name).
// Intervals that may be implemented in C++ will inherit
// from this class; Intervals that must be implemented
// in Python will inherit from the similar Python class.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CInterval : public TypedReferenceCount {
public:
CInterval(const string &name, double duration, bool open_ended);
PUBLISHED:
INLINE const string &get_name() const;
INLINE double get_duration() const;
INLINE bool get_open_ended() const;
enum EventType {
ET_initialize,
ET_instant,
ET_step,
ET_finalize,
ET_reverse_initialize,
ET_reverse_instant,
ET_reverse_finalize
};
INLINE void set_t(double t, EventType event = ET_step);
INLINE double get_t() const;
void setup_play(double start_time, double end_time, double play_rate);
int step_play();
// These functions control the actual playback of the interval.
virtual void initialize(double t);
virtual void instant();
virtual void step(double t);
virtual void finalize();
virtual void reverse_initialize(double t);
virtual void reverse_instant();
virtual void reverse_finalize();
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
public:
void mark_dirty();
protected:
INLINE void recompute() const;
virtual void do_recompute();
double _curr_t;
string _name;
double _duration;
// For setup_play() and step_play().
double _clock_start;
double _start_t;
double _end_t;
bool _end_t_at_end;
bool _start_t_at_start;
double _play_rate;
int _loop_count;
bool _restart;
private:
bool _open_ended;
bool _dirty;
// We keep a record of the "parent" intervals (that is, any
// CMetaInterval objects that keep a pointer to this one) strictly
// so we can mark all of our parents dirty when this interval gets
// dirty.
typedef pvector<CInterval *> Parents;
Parents _parents;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
register_type(_type_handle, "CInterval",
TypedReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class CMetaInterval;
};
INLINE ostream &operator << (ostream &out, const CInterval &ival);
#include "cInterval.I"
#endif

View File

@@ -0,0 +1,62 @@
// Filename: cLerpAnimEffectInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CLerpAnimEffectInterval::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE CLerpAnimEffectInterval::
CLerpAnimEffectInterval(const string &name, double duration,
CLerpInterval::BlendType blend_type) :
CLerpInterval(name, duration, blend_type)
{
}
////////////////////////////////////////////////////////////////////
// Function: CLerpAnimEffectInterval::add_control
// Access: Published
// Description: Adds another AnimControl to the list of AnimControls
// affected by the lerp. This control will be lerped
// from begin_effect to end_effect over the period of
// the lerp.
//
// The AnimControl name parameter is only used when
// formatting the interval for output.
////////////////////////////////////////////////////////////////////
INLINE void CLerpAnimEffectInterval::
add_control(AnimControl *control, const string &name,
float begin_effect, float end_effect) {
_controls.push_back(ControlDef(control, name, begin_effect, end_effect));
}
////////////////////////////////////////////////////////////////////
// Function: CLerpAnimEffectInterval::ControlDef::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CLerpAnimEffectInterval::ControlDef::
ControlDef(AnimControl *control, const string &name,
float begin_effect, float end_effect) :
_control(control),
_name(name),
_begin_effect(begin_effect),
_end_effect(end_effect)
{
}

View File

@@ -0,0 +1,70 @@
// Filename: cLerpAnimEffectInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cLerpAnimEffectInterval.h"
#include "lerp_helpers.h"
#include "partBundle.h"
TypeHandle CLerpAnimEffectInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CLerpAnimEffectInterval::step
// Access: Published, Virtual
// Description: Advances the time on the interval. The time may
// either increase (the normal case) or decrease
// (e.g. if the interval is being played by a slider).
////////////////////////////////////////////////////////////////////
void CLerpAnimEffectInterval::
step(double t) {
double d = compute_delta(t);
Controls::iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
ControlDef &def = (*ci);
float effect;
lerp_value(effect, d, def._begin_effect, def._end_effect);
def._control->get_part()->set_control_effect(def._control, effect);
}
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpAnimEffectInterval::output
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CLerpAnimEffectInterval::
output(ostream &out) const {
out << get_name() << ": ";
if (_controls.empty()) {
out << "(no controls)";
} else {
Controls::const_iterator ci;
ci = _controls.begin();
out << (*ci)._name;
++ci;
while (ci != _controls.end()) {
out << ", " << (*ci)._name;
++ci;
}
}
out << " dur " << get_duration();
}

View File

@@ -0,0 +1,87 @@
// Filename: cLerpAnimEffectInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CLERPANIMEFFECTINTERVAL_H
#define CLERPANIMEFFECTINTERVAL_H
#include "directbase.h"
#include "cLerpInterval.h"
#include "animControl.h"
#include "pointerTo.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : CLerpAnimEffectInterval
// Description : This interval lerps between different amounts of
// control effects for various AnimControls that might
// be playing on an actor. It's used to change the
// blending amount between multiple animations.
//
// The idea is to start all the animations playing
// first, then use a CLerpAnimEffectInterval to adjust
// the degree to which each animation affects the actor.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CLerpAnimEffectInterval : public CLerpInterval {
PUBLISHED:
INLINE CLerpAnimEffectInterval(const string &name, double duration,
BlendType blend_type);
INLINE void add_control(AnimControl *control, const string &name,
float begin_effect, float end_effect);
virtual void step(double t);
virtual void output(ostream &out) const;
private:
class ControlDef {
public:
INLINE ControlDef(AnimControl *control, const string &name,
float begin_effect, float end_effect);
PT(AnimControl) _control;
string _name;
float _begin_effect;
float _end_effect;
};
typedef pvector<ControlDef> Controls;
Controls _controls;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CLerpInterval::init_type();
register_type(_type_handle, "CLerpAnimEffectInterval",
CLerpInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cLerpAnimEffectInterval.I"
#endif

View File

@@ -0,0 +1,43 @@
// Filename: cLerpInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CLerpInterval::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CLerpInterval::
CLerpInterval(const string &name, double duration,
CLerpInterval::BlendType blend_type) :
CInterval(name, duration, true),
_blend_type(blend_type)
{
}
////////////////////////////////////////////////////////////////////
// Function: CLerpInterval::get_blend_type
// Access: Published
// Description: Returns the blend type specified for the interval.
// This controls how the linear interpolation behaves
// near the beginning and end of the lerp period.
////////////////////////////////////////////////////////////////////
INLINE CLerpInterval::BlendType CLerpInterval::
get_blend_type() const {
return _blend_type;
}

View File

@@ -0,0 +1,85 @@
// Filename: cLerpInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cLerpInterval.h"
#include "string_utils.h"
TypeHandle CLerpInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CLerpInterval::string_blend_type
// Access: Published, Static
// Description: Returns the BlendType enumerated value corresponding
// to the indicated string, or BT_invalid if the string
// doesn't match anything.
////////////////////////////////////////////////////////////////////
CLerpInterval::BlendType CLerpInterval::
string_blend_type(const string &blend_type) {
if (blend_type == "easeIn") {
return BT_ease_in;
} else if (blend_type == "easeOut") {
return BT_ease_out;
} else if (blend_type == "easeInOut") {
return BT_ease_in_out;
} else if (blend_type == "noBlend") {
return BT_no_blend;
} else {
return BT_invalid;
}
}
////////////////////////////////////////////////////////////////////
// Function: CLerpInterval::compute_delta
// Access: Protected
// Description: Given a t value in the range [0, get_duration()],
// returns the corresponding delta value clamped to the
// range [0, 1], after scaling by duration and applying
// the blend type.
////////////////////////////////////////////////////////////////////
double CLerpInterval::
compute_delta(double t) const {
double duration = get_duration();
if (duration == 0.0) {
return 0.0;
}
t /= duration;
t = min(max(t, 0.0), 1.0);
switch (_blend_type) {
case BT_ease_in:
{
double t2 = t * t;
return ((3.0 * t2) - (t2 * t)) * 0.5;
}
case BT_ease_out:
{
double t2 = t * t;
return ((3.0 * t2) - (t2 * t)) * 0.5;
}
case BT_ease_in_out:
{
double t2 = t * t;
return (3.0 * t2) - (2.0 * t * t2);
}
default:
return t;
}
}

View File

@@ -0,0 +1,78 @@
// Filename: cLerpInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CLERPINTERVAL_H
#define CLERPINTERVAL_H
#include "directbase.h"
#include "cInterval.h"
////////////////////////////////////////////////////////////////////
// Class : CLerpInterval
// Description : The base class for a family of intervals that
// linearly interpolate one or more numeric values over
// time.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CLerpInterval : public CInterval {
PUBLISHED:
enum BlendType {
BT_no_blend,
BT_ease_in,
BT_ease_out,
BT_ease_in_out,
BT_invalid
};
public:
INLINE CLerpInterval(const string &name, double duration,
BlendType blend_type);
PUBLISHED:
INLINE BlendType get_blend_type() const;
static BlendType string_blend_type(const string &blend_type);
protected:
double compute_delta(double t) const;
private:
BlendType _blend_type;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CInterval::init_type();
register_type(_type_handle, "CLerpInterval",
CInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cLerpInterval.I"
#endif

View File

@@ -0,0 +1,219 @@
// Filename: cLerpNodePathInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::get_node
// Access: Published
// Description: Returns the node being lerped.
////////////////////////////////////////////////////////////////////
INLINE const NodePath &CLerpNodePathInterval::
get_node() const {
return _node;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::get_other
// Access: Published
// Description: Returns the "other" node, which the lerped node is
// being moved relative to. If this is an empty node
// path, the lerped node is being moved in its own
// coordinate system.
////////////////////////////////////////////////////////////////////
INLINE const NodePath &CLerpNodePathInterval::
get_other() const {
return _other;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_pos
// Access: Published
// Description: Indicates the initial position of the lerped node.
// This is meaningful only if set_end_pos() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// position at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_pos(const LVecBase3f &pos) {
_start_pos = pos;
_flags |= F_start_pos;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_pos
// Access: Published
// Description: Indicates that the position of the node should be
// lerped, and specifies the final position of the node.
// This should be called before initialize(). If this
// is not called, the node's position will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_pos(const LVecBase3f &pos) {
_end_pos = pos;
_flags |= F_end_pos;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_hpr
// Access: Published
// Description: Indicates the initial rotation of the lerped node.
// This is meaningful only if set_end_hpr() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// rotation at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_hpr(const LVecBase3f &hpr) {
_start_hpr = hpr;
_flags |= F_start_hpr;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_hpr
// Access: Published
// Description: Indicates that the rotation of the node should be
// lerped, and specifies the final rotation of the node.
// This should be called before initialize(). If this
// is not called, the node's rotation will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_hpr(const LVecBase3f &hpr) {
_end_hpr = hpr;
_flags |= F_end_hpr;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_scale
// Access: Published
// Description: Indicates the initial scale of the lerped node.
// This is meaningful only if set_end_scale() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// scale at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_scale(const LVecBase3f &scale) {
_start_scale = scale;
_flags |= F_start_scale;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_scale
// Access: Published
// Description: Indicates the initial scale of the lerped node.
// This is meaningful only if set_end_scale() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// scale at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_scale(float scale) {
set_start_scale(LVecBase3f(scale, scale, scale));
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_scale
// Access: Published
// Description: Indicates that the scale of the node should be
// lerped, and specifies the final scale of the node.
// This should be called before initialize(). If this
// is not called, the node's scale will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_scale(const LVecBase3f &scale) {
_end_scale = scale;
_flags |= F_end_scale;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_scale
// Access: Published
// Description: Indicates that the scale of the node should be
// lerped, and specifies the final scale of the node.
// This should be called before initialize(). If this
// is not called, the node's scale will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_scale(float scale) {
set_end_scale(LVecBase3f(scale, scale, scale));
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_color
// Access: Published
// Description: Indicates the initial color of the lerped node.
// This is meaningful only if set_end_color() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// color at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_color(const LVecBase4f &color) {
_start_color = color;
_flags |= F_start_color;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_color
// Access: Published
// Description: Indicates that the color of the node should be
// lerped, and specifies the final color of the node.
// This should be called before initialize(). If this
// is not called, the node's color will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_color(const LVecBase4f &color) {
_end_color = color;
_flags |= F_end_color;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_start_color_scale
// Access: Published
// Description: Indicates the initial color scale of the lerped node.
// This is meaningful only if set_end_color_scale() is also
// called. This parameter is optional; if unspecified,
// the value will be taken from the node's actual
// color scale at the time the lerp is performed.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_start_color_scale(const LVecBase4f &color_scale) {
_start_color_scale = color_scale;
_flags |= F_start_color_scale;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::set_end_color_scale
// Access: Published
// Description: Indicates that the color scale of the node should be
// lerped, and specifies the final color scale of the node.
// This should be called before initialize(). If this
// is not called, the node's color scale will not be
// affected by the lerp.
////////////////////////////////////////////////////////////////////
INLINE void CLerpNodePathInterval::
set_end_color_scale(const LVecBase4f &color_scale) {
_end_color_scale = color_scale;
_flags |= F_end_color_scale;
}

View File

@@ -0,0 +1,351 @@
// Filename: cLerpNodePathInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cLerpNodePathInterval.h"
#include "lerp_helpers.h"
#include "transformState.h"
#include "renderState.h"
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "dcast.h"
TypeHandle CLerpNodePathInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::Constructor
// Access: Published
// Description: Constructs a lerp interval that will lerp some
// properties on the indicated node, possibly relative
// to the indicated other node (if other is nonempty).
//
// You must call set_end_pos(), etc. for the various
// properties you wish to lerp before the first call to
// initialize(). If you want to set a starting value
// for any of the properties, you may call
// set_start_pos(), etc.; otherwise, the starting value
// is taken from the actual node's value at the time the
// lerp is performed.
////////////////////////////////////////////////////////////////////
CLerpNodePathInterval::
CLerpNodePathInterval(const string &name, double duration,
CLerpInterval::BlendType blend_type,
const NodePath &node, const NodePath &other) :
CLerpInterval(name, duration, blend_type),
_node(node),
_other(other),
_flags(0)
{
_prev_d = 0.0;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::initialize
// Access: Published, Virtual
// Description: This replaces the first call to step(), and indicates
// that the interval has just begun. This may be
// overridden by derived classes that need to do some
// explicit initialization on the first call.
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
initialize(double t) {
recompute();
_prev_d = 0.0;
step(t);
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::instant
// Access: Published, Virtual
// Description: This is called in lieu of initialize() .. step()
// .. finalize(), when everything is to happen within
// one frame. The interval should initialize itself,
// then leave itself in the final state.
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
instant() {
recompute();
_prev_d = 0.0;
step(get_duration());
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::step
// Access: Published, Virtual
// Description: Advances the time on the interval. The time may
// either increase (the normal case) or decrease
// (e.g. if the interval is being played by a slider).
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
step(double t) {
double d = compute_delta(t);
if ((_flags & (F_end_pos | F_end_hpr | F_end_scale)) != 0) {
// We have some transform lerp.
CPT(TransformState) transform;
if (_other.is_empty()) {
// If there is no other node, it's a local transform lerp.
transform = _node.get_transform();
} else {
// If there *is* another node, we get the transform relative to
// that node.
transform = _node.get_transform(_other);
}
LPoint3f pos;
LVecBase3f hpr;
LVecBase3f scale;
if ((_flags & F_end_pos) != 0) {
if ((_flags & F_start_pos) != 0) {
lerp_value(pos, d, _start_pos, _end_pos);
} else {
pos = transform->get_pos();
lerp_value_from_prev(pos, d, _prev_d, pos, _end_pos);
}
}
if ((_flags & F_end_hpr) != 0) {
if ((_flags & F_start_hpr) != 0) {
lerp_value(hpr, d, _start_hpr, _end_hpr);
} else {
hpr = transform->get_hpr();
lerp_value_from_prev(hpr, d, _prev_d, hpr, _end_hpr);
}
}
if ((_flags & F_end_scale) != 0) {
if ((_flags & F_start_scale) != 0) {
lerp_value(scale, d, _start_scale, _end_scale);
} else {
scale = transform->get_scale();
lerp_value_from_prev(scale, d, _prev_d, scale, _end_scale);
}
}
// Now apply the modifications back to the transform. We want to
// be a little careful here, because we don't want to assume the
// transform has hpr/scale components if they're not needed. And
// in any case, we only want to apply the components that we
// computed, above.
switch (_flags & (F_end_pos | F_end_hpr | F_end_scale)) {
case F_end_pos:
transform = transform->set_pos(pos);
break;
case F_end_hpr:
transform = transform->set_hpr(hpr);
break;
case F_end_scale:
transform = transform->set_scale(scale);
break;
case F_end_hpr | F_end_scale:
transform = TransformState::make_pos_hpr_scale(transform->get_pos(), hpr, scale);
break;
case F_end_pos | F_end_hpr:
transform = TransformState::make_pos_hpr_scale(pos, hpr, transform->get_scale());
break;
case F_end_pos | F_end_scale:
if (transform->quat_given()) {
transform = TransformState::make_pos_quat_scale(pos, transform->get_quat(), scale);
} else {
transform = TransformState::make_pos_hpr_scale(pos, transform->get_hpr(), scale);
}
break;
case F_end_pos | F_end_hpr | F_end_scale:
transform = TransformState::make_pos_hpr_scale(pos, hpr, scale);
break;
default:
interval_cat.error()
<< "Internal error in CLerpNodePathInterval::step().\n";
}
// Now apply the new transform back to the node.
if (_other.is_empty()) {
_node.set_transform(transform);
} else {
_node.set_transform(_other, transform);
}
}
if ((_flags & (F_end_color | F_end_color_scale)) != 0) {
// We have some render state lerp.
CPT(RenderState) state;
if (_other.is_empty()) {
// If there is no other node, it's a local state lerp. This is
// most common.
state = _node.get_state();
} else {
// If there *is* another node, we get the state relative to that
// node. This is weird, but you could lerp color (for instance)
// relative to some other node's color.
state = _node.get_state(_other);
}
// Unlike in the transform case above, we can go ahead and modify
// the state immediately with each attribute change, since these
// attributes don't interrelate.
if ((_flags & F_end_color) != 0) {
Colorf color;
if ((_flags & F_start_color) != 0) {
lerp_value(color, d, _start_color, _end_color);
} else {
// Get the previous color.
color.set(1.0f, 1.0f, 1.0f, 1.0f);
const RenderAttrib *attrib =
state->get_attrib(ColorAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
if (ca->get_color_type() == ColorAttrib::T_flat) {
color = ca->get_color();
}
}
lerp_value_from_prev(color, d, _prev_d, color, _end_color);
}
state = state->add_attrib(ColorAttrib::make_flat(color));
}
if ((_flags & F_end_color_scale) != 0) {
LVecBase4f color_scale;
if ((_flags & F_start_color_scale) != 0) {
lerp_value(color_scale, d, _start_color_scale, _end_color_scale);
} else {
// Get the previous color scale.
color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
const RenderAttrib *attrib =
state->get_attrib(ColorScaleAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
color_scale = csa->get_scale();
}
lerp_value_from_prev(color_scale, d, _prev_d, color_scale, _end_color_scale);
}
state = state->add_attrib(ColorScaleAttrib::make(color_scale));
}
// Now apply the new state back to the node.
if (_other.is_empty()) {
_node.set_state(state);
} else {
_node.set_state(_other, state);
}
}
_prev_d = d;
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::reverse_initialize
// Access: Published, Virtual
// Description: Similar to initialize(), but this is called when the
// interval is being played backwards; it indicates that
// the interval should start at the finishing state and
// undo any intervening intervals.
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
reverse_initialize(double t) {
recompute();
_prev_d = 1.0;
step(t);
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::reverse_instant
// Access: Published, Virtual
// Description: This is called in lieu of reverse_initialize()
// .. step() .. reverse_finalize(), when everything is
// to happen within one frame. The interval should
// initialize itself, then leave itself in the initial
// state.
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
reverse_instant() {
recompute();
_prev_d = 1.0;
step(0.0);
}
////////////////////////////////////////////////////////////////////
// Function: CLerpNodePathInterval::output
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CLerpNodePathInterval::
output(ostream &out) const {
out << get_name() << ":";
if ((_flags & F_end_pos) != 0) {
out << " pos";
if ((_flags & F_start_pos) != 0) {
out << " from " << _start_pos;
}
out << " to " << _end_pos;
}
if ((_flags & F_end_hpr) != 0) {
out << " hpr";
if ((_flags & F_start_hpr) != 0) {
out << " from " << _start_hpr;
}
out << " to " << _end_hpr;
}
if ((_flags & F_end_scale) != 0) {
out << " scale";
if ((_flags & F_start_scale) != 0) {
out << " from " << _start_scale;
}
out << " to " << _end_scale;
}
if ((_flags & F_end_color) != 0) {
out << " color";
if ((_flags & F_start_color) != 0) {
out << " from " << _start_color;
}
out << " to " << _end_color;
}
if ((_flags & F_end_color_scale) != 0) {
out << " color_scale";
if ((_flags & F_start_color_scale) != 0) {
out << " from " << _start_color_scale;
}
out << " to " << _end_color_scale;
}
out << " dur " << get_duration();
}

View File

@@ -0,0 +1,109 @@
// Filename: cLerpNodePathInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CLERPNODEPATHINTERVAL_H
#define CLERPNODEPATHINTERVAL_H
#include "directbase.h"
#include "cLerpInterval.h"
#include "nodePath.h"
////////////////////////////////////////////////////////////////////
// Class : CLerpNodePathInterval
// Description : An interval that lerps one or more properties (like
// pos, hpr, etc.) on a NodePath over time.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CLerpNodePathInterval : public CLerpInterval {
PUBLISHED:
CLerpNodePathInterval(const string &name, double duration,
BlendType blend_type,
const NodePath &node, const NodePath &other);
INLINE const NodePath &get_node() const;
INLINE const NodePath &get_other() const;
INLINE void set_start_pos(const LVecBase3f &pos);
INLINE void set_end_pos(const LVecBase3f &pos);
INLINE void set_start_hpr(const LVecBase3f &hpr);
INLINE void set_end_hpr(const LVecBase3f &hpr);
INLINE void set_start_scale(const LVecBase3f &scale);
INLINE void set_start_scale(float scale);
INLINE void set_end_scale(const LVecBase3f &scale);
INLINE void set_end_scale(float scale);
INLINE void set_start_color(const LVecBase4f &color);
INLINE void set_end_color(const LVecBase4f &color);
INLINE void set_start_color_scale(const LVecBase4f &color_scale);
INLINE void set_end_color_scale(const LVecBase4f &color_scale);
virtual void initialize(double t);
virtual void instant();
virtual void step(double t);
virtual void reverse_initialize(double t);
virtual void reverse_instant();
virtual void output(ostream &out) const;
private:
NodePath _node;
NodePath _other;
enum Flags {
F_end_pos = 0x0001,
F_end_hpr = 0x0002,
F_end_scale = 0x0004,
F_end_color = 0x0008,
F_end_color_scale = 0x0010,
F_start_pos = 0x0100,
F_start_hpr = 0x0200,
F_start_scale = 0x0400,
F_start_color = 0x0800,
F_start_color_scale = 0x1000,
};
int _flags;
LPoint3f _start_pos, _end_pos;
LVecBase3f _start_hpr, _end_hpr;
LVecBase3f _start_scale, _end_scale;
Colorf _start_color, _end_color;
LVecBase4f _start_color_scale, _end_color_scale;
double _prev_d;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CLerpInterval::init_type();
register_type(_type_handle, "CLerpNodePathInterval",
CLerpInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cLerpNodePathInterval.I"
#endif

View File

@@ -0,0 +1,239 @@
// Filename: cMetaInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::set_precision
// Access: Published
// Description: Indicates the precision with which time measurements
// are compared. For numerical accuracy, all
// floating-point time values are converted to integer
// values internally by scaling by the precision factor.
// The larger the number given here, the smaller the
// delta of time that can be differentiated; the
// limit is the maximum integer that can be represented
// in the system.
////////////////////////////////////////////////////////////////////
INLINE void CMetaInterval::
set_precision(double precision) {
_precision = precision;
mark_dirty();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_precision
// Access: Published
// Description: Returns the precision with which time measurements
// are compared. See set_precision().
////////////////////////////////////////////////////////////////////
INLINE double CMetaInterval::
get_precision() const {
return _precision;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_num_defs
// Access: Published
// Description: Returns the number of interval and push/pop
// definitions that have been added to the meta
// interval.
////////////////////////////////////////////////////////////////////
INLINE int CMetaInterval::
get_num_defs() const {
return (int)_defs.size();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_def_type
// Access: Published
// Description: Returns the type of the nth interval definition that
// has been added.
////////////////////////////////////////////////////////////////////
INLINE CMetaInterval::DefType CMetaInterval::
get_def_type(int n) const {
nassertr(n >= 0 && n < (int)_defs.size(), DT_c_interval);
return _defs[n]._type;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_c_interval
// Access: Published
// Description: Return the CInterval pointer associated with the nth
// interval definition. It is only valid to call this
// if get_def_type(n) returns DT_c_interval.
////////////////////////////////////////////////////////////////////
INLINE CInterval *CMetaInterval::
get_c_interval(int n) const {
nassertr(n >= 0 && n < (int)_defs.size(), NULL);
nassertr(_defs[n]._type == DT_c_interval, NULL);
return _defs[n]._c_interval;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_ext_index
// Access: Published
// Description: Return the external interval index number associated
// with the nth interval definition. It is only valid
// to call this if get_def_type(n) returns DT_ext_index.
////////////////////////////////////////////////////////////////////
INLINE int CMetaInterval::
get_ext_index(int n) const {
nassertr(n >= 0 && n < (int)_defs.size(), NULL);
nassertr(_defs[n]._type == DT_ext_index, NULL);
return _defs[n]._ext_index;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::is_event_ready
// Access: Published
// Description: Returns true if a recent call to initialize(),
// step(), or finalize() has left some external
// intervals ready to play. If this returns true, call
// get_event_index(), get_event_t(), and pop_event() to
// retrieve the relevant information.
////////////////////////////////////////////////////////////////////
INLINE bool CMetaInterval::
is_event_ready() {
return service_event_queue();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_event_index
// Access: Published
// Description: If a previous call to is_event_ready() returned
// true, this returns the index number (added via
// add_event_index()) of the external interval that needs
// to be played.
////////////////////////////////////////////////////////////////////
INLINE int CMetaInterval::
get_event_index() const {
nassertr(!_event_queue.empty(), -1);
const EventQueueEntry &entry = _event_queue.front();
const IntervalDef &def = _defs[entry._n];
nassertr(def._type == DT_ext_index, -1);
return def._ext_index;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_event_t
// Access: Published
// Description: If a previous call to is_event_ready() returned
// true, this returns the t value that should be fed to
// the given interval.
////////////////////////////////////////////////////////////////////
INLINE double CMetaInterval::
get_event_t() const {
nassertr(!_event_queue.empty(), 0.0f);
return int_to_double_time(_event_queue.front()._time);
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_event_type
// Access: Published
// Description: If a previous call to is_event_ready() returned
// true, this returns the type of the event (initialize,
// step, finalize, etc.) for the given interval.
////////////////////////////////////////////////////////////////////
INLINE CInterval::EventType CMetaInterval::
get_event_type() const {
nassertr(!_event_queue.empty(), ET_step);
return _event_queue.front()._event_type;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::pop_event
// Access: Published
// Description: Acknowledges that the external interval on the top of
// the queue has been extracted, and is about to be
// serviced by the scripting language. This prepares
// the interval so the next call to is_event_ready()
// will return information about the next external
// interval on the queue, if any.
////////////////////////////////////////////////////////////////////
INLINE void CMetaInterval::
pop_event() {
#ifndef NDEBUG
nassertv(!_event_queue.empty());
const EventQueueEntry &entry = _event_queue.front();
const IntervalDef &def = _defs[entry._n];
nassertv(def._type == DT_ext_index);
#endif
_event_queue.pop_front();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::double_to_int_time
// Access: Private
// Description: Converts from an external double time value or offset
// in seconds to an internal integer value or offset.
////////////////////////////////////////////////////////////////////
INLINE int CMetaInterval::
double_to_int_time(double t) const {
// Use floor() just in case there are negative values involved.
return (int)floor(t * _precision + 0.5);
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::int_to_double_time
// Access: Private
// Description: Converts from an internal integer time value or
// offset to an external double time value or offset in
// seconds.
////////////////////////////////////////////////////////////////////
INLINE double CMetaInterval::
int_to_double_time(int time) const {
return (double)time / _precision;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::PlaybackEvent::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CMetaInterval::PlaybackEvent::
PlaybackEvent(int time, int n,
CMetaInterval::PlaybackEventType type) :
_time(time),
_n(n),
_type(type)
{
_begin_event = this;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::PlaybackEvent::Ordering operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool CMetaInterval::PlaybackEvent::
operator < (const CMetaInterval::PlaybackEvent &other) const {
return _time < other._time;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::EventQueueEntry::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CMetaInterval::EventQueueEntry::
EventQueueEntry(int n, CInterval::EventType event_type, int time) :
_n(n),
_event_type(event_type),
_time(time)
{
}

View File

@@ -0,0 +1,877 @@
// Filename: cMetaInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cMetaInterval.h"
#include "config_interval.h"
#include "indirectLess.h"
#include <algorithm>
#include <math.h> // for log10()
#include <stdio.h> // for sprintf()
TypeHandle CMetaInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
CMetaInterval::
CMetaInterval(const string &name) :
CInterval(name, 0.0, true)
{
_precision = interval_precision;
_current_nesting_level = 0;
_next_event_index = 0;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CMetaInterval::
~CMetaInterval() {
clear_intervals();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::clear_intervals
// Access: Published
// Description: Resets the list of intervals and prepares for
// receiving a new list.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
clear_intervals() {
// Better not do this unless you have serviced all of the
// outstanding events!
nassertv(_event_queue.empty());
clear_events();
// Go through all of our nested intervals and remove ourselves as
// their parent.
Defs::iterator di;
for (di = _defs.begin(); di != _defs.end(); ++di) {
IntervalDef &def = (*di);
if (def._c_interval != (CInterval *)NULL) {
CInterval::Parents::iterator pi =
find(def._c_interval->_parents.begin(),
def._c_interval->_parents.end(),
this);
nassertv(pi != def._c_interval->_parents.end());
def._c_interval->_parents.erase(pi);
}
}
_defs.clear();
_current_nesting_level = 0;
_next_event_index = 0;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::push_level
// Access: Published
// Description: Marks the beginning of a nested level of child
// intervals. Within the nested level, a RelativeStart
// time of RS_level_begin refers to the start of the
// level, and the first interval added within the level
// is always relative to the start of the level.
//
// The return value is the index of the def entry
// created by this push.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
push_level(double rel_time, RelativeStart rel_to) {
_defs.push_back(IntervalDef());
IntervalDef &def = _defs.back();
def._type = DT_push_level;
def._rel_time = rel_time;
def._rel_to = rel_to;
_current_nesting_level++;
mark_dirty();
return (int)_defs.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::add_c_interval
// Access: Published
// Description: Adds a new CInterval to the list. The interval will
// be played when the indicated time (relative to the
// given point) has been reached.
//
// The return value is the index of the def entry
// representing the new interval.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
add_c_interval(CInterval *c_interval,
double rel_time, RelativeStart rel_to) {
nassertr(c_interval != (CInterval *)NULL, -1);
c_interval->_parents.push_back(this);
_defs.push_back(IntervalDef());
IntervalDef &def = _defs.back();
def._type = DT_c_interval;
def._c_interval = c_interval;
def._rel_time = rel_time;
def._rel_to = rel_to;
mark_dirty();
return (int)_defs.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::add_ext_index
// Access: Published
// Description: Adds a new external interval to the list. This
// represents some object in the external scripting
// language that has properties similar to a CInterval
// (for instance, a Python Interval object).
//
// The CMetaInterval object cannot play this external
// interval directly, but it records a placeholder for
// it and will ask the scripting language to play it
// when it is time, via is_event_ready() and related
// methods.
//
// The ext_index number itself is simply a handle that
// the scripting language makes up and associates with
// its interval object somehow. The CMetaInterval
// object does not attempt to interpret this value.
//
// The return value is the index of the def entry
// representing the new interval.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
add_ext_index(int ext_index, const string &name, double duration,
bool open_ended,
double rel_time, RelativeStart rel_to) {
_defs.push_back(IntervalDef());
IntervalDef &def = _defs.back();
def._type = DT_ext_index;
def._ext_index = ext_index;
def._ext_name = name;
def._ext_duration = duration;
def._ext_open_ended = open_ended;
def._rel_time = rel_time;
def._rel_to = rel_to;
mark_dirty();
return (int)_defs.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::pop_level
// Access: Published
// Description: Finishes a level marked by a previous call to
// push_level(), and returns to the previous level.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
pop_level() {
nassertr(_current_nesting_level > 0, -1);
_defs.push_back(IntervalDef());
IntervalDef &def = _defs.back();
def._type = DT_pop_level;
_current_nesting_level--;
mark_dirty();
return (int)_defs.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::initialize
// Access: Published, Virtual
// Description: This replaces the first call to step(), and indicates
// that the interval has just begun. This may be
// overridden by derived classes that need to do some
// explicit initialization on the first call.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
initialize(double t) {
// It may be tempting to flush the event_queue here, but don't do
// it. Those are events that must still be serviced from some
// previous interval operation. Throwing them away would be a
// mistake.
recompute();
_next_event_index = 0;
_active.clear();
int now = double_to_int_time(t);
// Now look for events from the beginning up to the current time.
ActiveEvents new_active;
while (_next_event_index < _events.size() &&
_events[_next_event_index]->_time <= now) {
PlaybackEvent *event = _events[_next_event_index];
// Do the indicated event.
do_event_forward(event, new_active, true);
_next_event_index++;
}
finish_events_forward(now, new_active);
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::instant
// Access: Published, Virtual
// Description: This is called in lieu of initialize() .. step()
// .. finalize(), when everything is to happen within
// one frame. The interval should initialize itself,
// then leave itself in the final state.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
instant() {
recompute();
_active.clear();
// Apply all of the events. This just means we invoke "instant" for
// any end or instant event, ignoring the begin events.
PlaybackEvents::iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
PlaybackEvent *event = (*ei);
if (event->_type != PET_begin) {
enqueue_event(event->_n, ET_instant, true, 0);
}
}
_next_event_index = _events.size();
_curr_t = get_duration();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::step
// Access: Published, Virtual
// Description: Advances the time on the interval. The time may
// either increase (the normal case) or decrease
// (e.g. if the interval is being played by a slider).
////////////////////////////////////////////////////////////////////
void CMetaInterval::
step(double t) {
int now = double_to_int_time(t);
// Now look for events between the last time we ran and the current
// time.
if (_next_event_index < _events.size() &&
_events[_next_event_index]->_time <= now) {
// The normal case: time is increasing.
ActiveEvents new_active;
while (_next_event_index < _events.size() &&
_events[_next_event_index]->_time <= now) {
PlaybackEvent *event = _events[_next_event_index];
// Do the indicated event.
do_event_forward(event, new_active, false);
_next_event_index++;
}
finish_events_forward(now, new_active);
} else {
// A less usual case: time is decreasing.
ActiveEvents new_active;
while (_next_event_index > 0 &&
_events[_next_event_index - 1]->_time > now) {
_next_event_index--;
PlaybackEvent *event = _events[_next_event_index];
do_event_reverse(event, new_active, false);
}
finish_events_reverse(now, new_active);
}
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::finalize
// Access: Published, Virtual
// Description: This is called when an interval is interrupted. It
// should advance the time as if step() were called, and
// also perform whatever cleanup might be required.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
finalize() {
// Do all remaining events.
ActiveEvents new_active;
while (_next_event_index < _events.size()) {
PlaybackEvent *event = _events[_next_event_index];
// Do the indicated event.
do_event_forward(event, new_active, false);
_next_event_index++;
}
_curr_t = get_duration();
finish_events_forward(double_to_int_time(_curr_t), new_active);
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::reverse_initialize
// Access: Published, Virtual
// Description: Similar to initialize(), but this is called when the
// interval is being played backwards; it indicates that
// the interval should start at the finishing state and
// undo any intervening intervals.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
reverse_initialize(double t) {
// It may be tempting to flush the event_queue here, but don't do
// it. Those are events that must still be serviced from some
// previous interval operation. Throwing them away would be a
// mistake.
recompute();
_next_event_index = _events.size();
_active.clear();
int now = double_to_int_time(t);
// Now look for events from the end down to the current time.
ActiveEvents new_active;
while (_next_event_index > 0 &&
_events[_next_event_index - 1]->_time > now) {
_next_event_index--;
PlaybackEvent *event = _events[_next_event_index];
// Do the indicated event.
do_event_reverse(event, new_active, true);
}
finish_events_reverse(now, new_active);
_curr_t = t;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::reverse_instant
// Access: Published, Virtual
// Description: This is called in lieu of reverse_initialize()
// .. step() .. reverse_finalize(), when everything is
// to happen within one frame. The interval should
// initialize itself, then leave itself in the initial
// state.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
reverse_instant() {
recompute();
_active.clear();
// Apply all of the events. This just means we invoke "instant" for
// any end or instant event, ignoring the begin events.
PlaybackEvents::reverse_iterator ei;
for (ei = _events.rbegin(); ei != _events.rend(); ++ei) {
PlaybackEvent *event = (*ei);
if (event->_type != PET_begin) {
enqueue_event(event->_n, ET_reverse_instant, true, 0);
}
}
_next_event_index = 0;
_curr_t = 0.0;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::reverse_finalize
// Access: Published, Virtual
// Description: Called generally following a reverse_initialize(),
// this indicates the interval should set itself to the
// initial state.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
reverse_finalize() {
// Do all remaining events at the beginning.
ActiveEvents new_active;
while (_next_event_index > 0) {
_next_event_index--;
PlaybackEvent *event = _events[_next_event_index];
do_event_reverse(event, new_active, false);
}
finish_events_reverse(0, new_active);
_curr_t = 0.0;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::write
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CMetaInterval::
write(ostream &out, int indent_level) const {
recompute();
// How many digits of precision should we output for time?
int num_decimals = (int)ceil(log10(_precision));
int total_digits = num_decimals + 4;
static const int max_digits = 32; // totally arbitrary
nassertv(total_digits <= max_digits);
char format_str[12];
sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
indent(out, indent_level) << get_name() << ":\n";
int extra_indent_level = 1;
Defs::const_iterator di;
for (di = _defs.begin(); di != _defs.end(); ++di) {
const IntervalDef &def = (*di);
char time_str[max_digits + 1];
sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time));
indent(out, indent_level) << time_str;
switch (def._type) {
case DT_c_interval:
indent(out, extra_indent_level)
<< *def._c_interval;
if (!def._c_interval->get_open_ended()) {
out << " (!oe)";
}
out << "\n";
break;
case DT_ext_index:
indent(out, extra_indent_level)
<< "*" << def._ext_name;
if (def._ext_duration != 0.0) {
out << " dur " << def._ext_duration;
}
if (!def._ext_open_ended) {
out << " (!oe)";
}
out<< "\n";
break;
case DT_push_level:
indent(out, extra_indent_level)
<< "{\n";
extra_indent_level += 2;
break;
case DT_pop_level:
extra_indent_level -= 2;
indent(out, extra_indent_level)
<< "}\n";
break;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::do_recompute
// Access: Protected, Virtual
// Description: Recomputes all of the events (and the duration)
// according to the set of interval defs.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
do_recompute() {
_dirty = false;
clear_events();
int n = recompute_level(0, 0, _end_time);
if (n != (int)_defs.size()) {
interval_cat.warning()
<< "CMetaInterval pushes don't match pops.\n";
}
// We do a stable_sort() to guarantee ordering of events that have
// the same start time. These must be invoked in the order in which
// they appear.
stable_sort(_events.begin(), _events.end(), IndirectLess<PlaybackEvent>());
_duration = int_to_double_time(_end_time);
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::clear_events
// Access: Private
// Description: Removes all entries from the _events list.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
clear_events() {
PlaybackEvents::iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
PlaybackEvent *event = (*ei);
delete event;
}
_events.clear();
_active.clear();
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::do_event_forward
// Access: Private
// Description: Process a single event in the interval, moving
// forwards in time. If the event represents a new
// begin, adds it to the new_active list; if it is an
// end, finalizes it.
//
// If is_initial is true, it is as if we are in
// initialize: instant events will be invoked only if
// they are marked open_ended.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
do_event_forward(CMetaInterval::PlaybackEvent *event,
CMetaInterval::ActiveEvents &new_active, bool is_initial) {
switch (event->_type) {
case PET_begin:
{
nassertv(event->_begin_event == event);
nassertv(_active.find(event) == _active.end());
bool okflag = new_active.insert(event).second;
nassertv(okflag);
}
break;
case PET_end:
{
// Erase the event from either the new active or the current
// active lists.
int erase_count = new_active.erase(event->_begin_event);
if (erase_count != 0) {
// This interval was new this frame; we must invoke it as
// an instant event.
enqueue_event(event->_n, ET_instant, is_initial);
} else {
erase_count = _active.erase(event->_begin_event);
enqueue_event(event->_n, ET_finalize, is_initial);
}
nassertv(erase_count == 1);
}
break;
case PET_instant:
nassertv(event->_begin_event == event);
nassertv(new_active.find(event) == new_active.end());
nassertv(_active.find(event) == _active.end());
enqueue_event(event->_n, ET_instant, is_initial);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::finish_events_forward
// Access: Private
// Description: After walking through the event list and adding a
// bunch of new events to new_active, finished up by
// calling step() on all of the events still in _active
// and initialize() on all the events in new_active,
// then copying the events from new_active to active.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
finish_events_forward(int now, CMetaInterval::ActiveEvents &new_active) {
// Do whatever's still active.
ActiveEvents::iterator ai;
for (ai = _active.begin(); ai != _active.end(); ++ai) {
PlaybackEvent *event = (*ai);
enqueue_event(event->_n, ET_step, false, now - event->_time);
}
// Initialize whatever new intervals we came across.
for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
PlaybackEvent *event = (*ai);
enqueue_event(event->_n, ET_initialize, false, now - event->_time);
bool inserted = _active.insert(event).second;
nassertv(inserted);
}
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::do_event_reverse
// Access: Private
// Description: Process a single event in the interval, moving
// backwards in time. This undoes the indicated event.
// If the event represents a new begin, adds it to the
// new_active list; if it is an end, finalizes it.
//
// If is_initial is true, it is as if we are in
// reverse_initialize: instant events will be invoked
// only if they are marked open_ended.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
do_event_reverse(CMetaInterval::PlaybackEvent *event,
CMetaInterval::ActiveEvents &new_active, bool is_initial) {
// Undo the indicated event.
switch (event->_type) {
case PET_begin:
{
nassertv(event->_begin_event == event);
// Erase the event from either the new active or the current
// active lists.
int erase_count = new_active.erase(event);
if (erase_count != 0) {
// This interval was new this frame; we invoke it as an
// instant event.
enqueue_event(event->_n, ET_reverse_instant, is_initial);
} else {
erase_count = _active.erase(event->_begin_event);
enqueue_event(event->_n, ET_reverse_finalize, is_initial);
}
nassertv(erase_count == 1);
}
break;
case PET_end:
{
nassertv(new_active.find(event->_begin_event) == new_active.end());
bool okflag = new_active.insert(event->_begin_event).second;
nassertv(okflag);
}
break;
case PET_instant:
nassertv(event->_begin_event == event);
nassertv(_active.find(event) == _active.end());
nassertv(new_active.find(event) == new_active.end());
enqueue_event(event->_n, ET_reverse_instant, is_initial);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::finish_events_reverse
// Access: Private
// Description: After walking through the event list and adding a
// bunch of new events to new_active, finishes up by
// calling step() on all of the events still in _active
// and reverse_initialize() on all the events in
// new_active, then copying the events from new_active
// to active.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
finish_events_reverse(int now, CMetaInterval::ActiveEvents &new_active) {
// Do whatever's still active.
ActiveEvents::iterator ai;
for (ai = _active.begin(); ai != _active.end(); ++ai) {
PlaybackEvent *event = (*ai);
enqueue_event(event->_n, ET_step, false, now - event->_time);
}
// Initialize whatever new intervals we came across.
for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
PlaybackEvent *event = (*ai);
enqueue_event(event->_n, ET_reverse_initialize, false, now - event->_time);
bool inserted = _active.insert(event).second;
nassertv(inserted);
}
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::enqueue_event
// Access: Private
// Description: Enqueues the indicated interval for invocation after
// we have finished scanning for events that need
// processing this frame.
//
// is_initial is only relevant for event types
// ET_instant or ET_reverse_instant, and indicates
// whether we are in the initialize() (or
// reverse_initialize()) call, and should therefore only
// invoke open-ended intervals.
//
// time is only relevant for ET_initialize,
// ET_reverse_initialize, and ET_step.
////////////////////////////////////////////////////////////////////
void CMetaInterval::
enqueue_event(int n, CInterval::EventType event_type, bool is_initial, int time) {
nassertv(n >= 0 && n < (int)_defs.size());
const IntervalDef &def = _defs[n];
switch (def._type) {
case DT_c_interval:
if (is_initial &&
(event_type == ET_instant || event_type == ET_reverse_instant) &&
!def._c_interval->get_open_ended()) {
// Ignore a non-open-ended interval that we skipped completely
// past on initialize().
return;
} else {
if (_event_queue.empty()) {
// if the event queue is empty, we can process this C++
// interval immediately. We only need to defer it if there
// are external (e.g. Python) intervals in the queue that need
// to be processed first.
def._c_interval->set_t(int_to_double_time(time), event_type);
return;
}
}
break;
case DT_ext_index:
if (is_initial &&
(event_type == ET_instant || event_type == ET_reverse_instant) &&
!def._ext_open_ended) {
// Ignore a non-open-ended interval that we skipped completely
// past on initialize().
return;
}
break;
default:
nassertv(false);
return;
}
_event_queue.push_back(EventQueueEntry(n, event_type, time));
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::service_event_queue
// Access: Private
// Description: Invokes whatever C++ intervals might be at the head
// of the queue, and prepares for passing an external
// interval to the scripting language.
//
// The return value is true if there remains at least
// one external event to be serviced, false if all
// events are handled.
////////////////////////////////////////////////////////////////////
bool CMetaInterval::
service_event_queue() {
while (!_event_queue.empty()) {
const EventQueueEntry &entry = _event_queue.front();
nassertr(entry._n >= 0 && entry._n < (int)_defs.size(), false);
const IntervalDef &def = _defs[entry._n];
switch (def._type) {
case DT_c_interval:
// Handle the C++ event.
def._c_interval->set_t(int_to_double_time(entry._time), entry._event_type);
break;
case DT_ext_index:
// Here's an external event; leave it there and return.
return true;
default:
nassertr(false, false);
return false;
}
_event_queue.pop_front();
}
// No more events on the queue.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::recompute_level
// Access: Private
// Description: Recursively recomputes a complete level (delimited by
// push/pop definitions).
//
// The value n on entry refers to the first entry after
// the push; the return value will reference the
// matching pop, or an index greater than the last
// element in the array if there was no matching pop.
//
// The level_begin value indicates the begin time of
// this level. On return, level_end is filled with the
// end time of this level.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
recompute_level(int n, int level_begin, int &level_end) {
level_end = level_begin;
int previous_begin = level_begin;
int previous_end = level_begin;
while (n < (int)_defs.size() && _defs[n]._type != DT_pop_level) {
IntervalDef &def = _defs[n];
int begin_time, end_time;
switch (def._type) {
case DT_c_interval:
begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
def._actual_begin_time = begin_time;
end_time = begin_time + double_to_int_time(def._c_interval->get_duration());
if (begin_time == end_time) {
_events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
} else {
PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
end->_begin_event = begin;
_events.push_back(begin);
_events.push_back(end);
}
break;
case DT_ext_index:
begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
def._actual_begin_time = begin_time;
end_time = begin_time + double_to_int_time(def._ext_duration);
if (begin_time == end_time) {
_events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
} else {
PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
end->_begin_event = begin;
_events.push_back(begin);
_events.push_back(end);
}
break;
case DT_push_level:
begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
def._actual_begin_time = begin_time;
n = recompute_level(n + 1, begin_time, end_time);
break;
case DT_pop_level:
nassertr(false, _defs.size());
break;
}
previous_begin = begin_time;
previous_end = end_time;
level_end = max(level_end, end_time);
n++;
}
if (n < (int)_defs.size()) {
// The final pop "begins" at the level end time, just for clarity
// on output.
IntervalDef &def = _defs[n];
def._actual_begin_time = level_end;
}
return n;
}
////////////////////////////////////////////////////////////////////
// Function: CMetaInterval::get_begin_time
// Access: Private
// Description: Returns the integer begin time indicated by the given
// IntervalDef, given the indicated level begin,
// previous begin, and previous end times.
////////////////////////////////////////////////////////////////////
int CMetaInterval::
get_begin_time(const CMetaInterval::IntervalDef &def, int level_begin,
int previous_begin, int previous_end) {
switch (def._rel_to) {
case RS_previous_end:
return previous_end + double_to_int_time(def._rel_time);
case RS_previous_begin:
return previous_begin + double_to_int_time(def._rel_time);
case RS_level_begin:
return level_begin + double_to_int_time(def._rel_time);
}
nassertr(false, previous_end);
return previous_end;
}

View File

@@ -0,0 +1,190 @@
// Filename: cMetaInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CMETAINTERVAL_H
#define CMETAINTERVAL_H
#include "directbase.h"
#include "cInterval.h"
#include <pdeque.h>
#include <pvector.h>
#include <pset.h>
////////////////////////////////////////////////////////////////////
// Class : CMetaInterval
// Description : This interval contains a list of nested intervals,
// each of which has its own begin and end times. Some
// of them may overlap and some of them may not.
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT CMetaInterval : public CInterval {
PUBLISHED:
CMetaInterval(const string &name);
virtual ~CMetaInterval();
enum RelativeStart {
RS_previous_end,
RS_previous_begin,
RS_level_begin,
};
INLINE void set_precision(double precision);
INLINE double get_precision() const;
void clear_intervals();
int push_level(double rel_time, RelativeStart rel_to);
int add_c_interval(CInterval *c_interval,
double rel_time, RelativeStart rel_to);
int add_ext_index(int ext_index, const string &name,
double duration, bool open_ended,
double rel_time, RelativeStart rel_to);
int pop_level();
enum DefType {
DT_c_interval,
DT_ext_index,
DT_push_level,
DT_pop_level
};
INLINE int get_num_defs() const;
INLINE DefType get_def_type(int n) const;
INLINE CInterval *get_c_interval(int n) const;
INLINE int get_ext_index(int n) const;
virtual void initialize(double t);
virtual void instant();
virtual void step(double t);
virtual void finalize();
virtual void reverse_initialize(double t);
virtual void reverse_instant();
virtual void reverse_finalize();
INLINE bool is_event_ready();
INLINE int get_event_index() const;
INLINE double get_event_t() const;
INLINE EventType get_event_type() const;
INLINE void pop_event();
virtual void write(ostream &out, int indent_level) const;
protected:
virtual void do_recompute();
private:
class IntervalDef {
public:
DefType _type;
PT(CInterval) _c_interval;
int _ext_index;
string _ext_name;
double _ext_duration;
bool _ext_open_ended;
double _rel_time;
RelativeStart _rel_to;
int _actual_begin_time;
};
enum PlaybackEventType {
PET_begin,
PET_end,
PET_instant
};
class PlaybackEvent {
public:
INLINE PlaybackEvent(int time, int n, PlaybackEventType type);
INLINE bool operator < (const PlaybackEvent &other) const;
int _time;
int _n;
PlaybackEventType _type;
PlaybackEvent *_begin_event;
};
class EventQueueEntry {
public:
INLINE EventQueueEntry(int n, EventType event_type, int time);
int _n;
EventType _event_type;
int _time;
};
typedef pvector<IntervalDef> Defs;
typedef pvector<PlaybackEvent *> PlaybackEvents;
typedef pset<PlaybackEvent *> ActiveEvents;
typedef pdeque<EventQueueEntry> EventQueue;
INLINE int double_to_int_time(double t) const;
INLINE double int_to_double_time(int time) const;
void clear_events();
void do_event_forward(PlaybackEvent *event, ActiveEvents &new_active,
bool is_initial);
void finish_events_forward(int now, ActiveEvents &new_active);
void do_event_reverse(PlaybackEvent *event, ActiveEvents &new_active,
bool is_initial);
void finish_events_reverse(int now, ActiveEvents &new_active);
void enqueue_event(int n, CInterval::EventType event_type, bool is_initial,
int time = 0);
bool service_event_queue();
int recompute_level(int n, int level_begin, int &level_end);
int get_begin_time(const IntervalDef &def, int level_begin,
int previous_begin, int previous_end);
double _precision;
Defs _defs;
int _current_nesting_level;
PlaybackEvents _events;
ActiveEvents _active;
int _end_time;
size_t _next_event_index;
// This is the queue of events that have occurred due to a recent
// initialize(), step(), etc., but have not yet been serviced, due
// to an embedded external (e.g. Python) interval that the scripting
// language must service. This queue should be considered precious,
// and should never be arbitrarily flushed without servicing all of
// its events.
EventQueue _event_queue;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CInterval::init_type();
register_type(_type_handle, "CMetaInterval",
CInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "cMetaInterval.I"
#endif

View File

@@ -0,0 +1,65 @@
// Filename: config_interval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "config_interval.h"
#include "cInterval.h"
#include "cLerpInterval.h"
#include "cLerpNodePathInterval.h"
#include "cLerpAnimEffectInterval.h"
#include "cMetaInterval.h"
#include "showInterval.h"
#include "hideInterval.h"
#include "dconfig.h"
Configure(config_interval);
NotifyCategoryDef(interval, "");
ConfigureFn(config_interval) {
init_libinterval();
}
// Set this to the default value for set_precision() for each
// CMetaInterval created.
const double interval_precision = config_interval.GetDouble("interval-precision", 1000.0);
////////////////////////////////////////////////////////////////////
// Function: init_libinterval
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libinterval() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
CInterval::init_type();
CLerpInterval::init_type();
CLerpNodePathInterval::init_type();
CLerpAnimEffectInterval::init_type();
CMetaInterval::init_type();
ShowInterval::init_type();
HideInterval::init_type();
}

View File

@@ -0,0 +1,32 @@
// Filename: config_interval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_INTERVAL_H
#define CONFIG_INTERVAL_H
#include "directbase.h"
#include "notifyCategoryProxy.h"
#include "dconfig.h"
NotifyCategoryDecl(interval, EXPCL_DIRECT, EXPTP_DIRECT);
extern const double interval_precision;
extern EXPCL_DIRECT void init_libinterval();
#endif

View File

@@ -0,0 +1,18 @@
// Filename: hideInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,68 @@
// Filename: hideInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "hideInterval.h"
int HideInterval::_unique_index;
TypeHandle HideInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: HideInterval::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
HideInterval::
HideInterval(const NodePath &node, const string &name) :
CInterval(name, 0.0, true),
_node(node)
{
nassertv(!node.is_empty());
if (_name.empty()) {
ostringstream name_strm;
name_strm
<< "HideInterval-" << node.node()->get_name() << "-" << ++_unique_index;
_name = name_strm.str();
}
}
////////////////////////////////////////////////////////////////////
// Function: HideInterval::instant
// Access: Published, Virtual
// Description: This is called in lieu of initialize() .. step()
// .. finalize(), when everything is to happen within
// one frame. The interval should initialize itself,
// then leave itself in the final state.
////////////////////////////////////////////////////////////////////
void HideInterval::
instant() {
_node.hide();
}
////////////////////////////////////////////////////////////////////
// Function: HideInterval::reverse_instant
// Access: Published, Virtual
// Description: This is called in lieu of reverse_initialize()
// .. step() .. reverse_finalize(), when everything is
// to happen within one frame. The interval should
// initialize itself, then leave itself in the initial
// state.
////////////////////////////////////////////////////////////////////
void HideInterval::
reverse_instant() {
_node.show();
}

View File

@@ -0,0 +1,61 @@
// Filename: hideInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef HIDEINTERVAL_H
#define HIDEINTERVAL_H
#include "directbase.h"
#include "cInterval.h"
////////////////////////////////////////////////////////////////////
// Class : HideInterval
// Description : An interval that calls NodePath::hide().
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT HideInterval : public CInterval {
PUBLISHED:
HideInterval(const NodePath &node, const string &name = string());
virtual void instant();
virtual void reverse_instant();
private:
NodePath _node;
static int _unique_index;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CInterval::init_type();
register_type(_type_handle, "HideInterval",
CInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "hideInterval.I"
#endif

View File

@@ -0,0 +1,75 @@
// Filename: lerp_helpers.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef LERP_HELPERS_H
#define LERP_HELPERS_H
#include "directbase.h"
//
// This header file is only included within .cxx files in this
// directory.
//
//
// The functions defined here include some trivial template functions
// for handling basic lerp computations, common to several .cxx files
// here.
//
////////////////////////////////////////////////////////////////////
// Function: lerp_value
// Description: Applies the linear lerp computation for a single
// parameter.
////////////////////////////////////////////////////////////////////
template<class NumericType>
INLINE void
lerp_value(NumericType &current_value,
double d,
const NumericType &starting_value,
const NumericType &ending_value) {
current_value = starting_value + d * (ending_value - starting_value);
}
////////////////////////////////////////////////////////////////////
// Function: lerp_value_from_prev
// Description: Applies the linear lerp computation for a single
// parameter, when the starting value is implicit.
//
// This computes the new value based on assuming the
// prev_value represents the value computed at delta
// prev_d.
////////////////////////////////////////////////////////////////////
template<class NumericType>
INLINE void
lerp_value_from_prev(NumericType &current_value,
double d, double prev_d,
const NumericType &prev_value,
const NumericType &ending_value) {
if (prev_d == 1.0) {
current_value = ending_value;
} else {
NumericType starting_value =
(prev_value - prev_d * ending_value) / (1.0 - prev_d);
current_value = starting_value + d * (ending_value - starting_value);
}
}
#endif

View File

@@ -0,0 +1,18 @@
// Filename: showInterval.I
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,68 @@
// Filename: showInterval.cxx
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "showInterval.h"
int ShowInterval::_unique_index;
TypeHandle ShowInterval::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ShowInterval::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
ShowInterval::
ShowInterval(const NodePath &node, const string &name) :
CInterval(name, 0.0, true),
_node(node)
{
nassertv(!node.is_empty());
if (_name.empty()) {
ostringstream name_strm;
name_strm
<< "ShowInterval-" << node.node()->get_name() << "-" << ++_unique_index;
_name = name_strm.str();
}
}
////////////////////////////////////////////////////////////////////
// Function: ShowInterval::instant
// Access: Published, Virtual
// Description: This is called in lieu of initialize() .. step()
// .. finalize(), when everything is to happen within
// one frame. The interval should initialize itself,
// then leave itself in the final state.
////////////////////////////////////////////////////////////////////
void ShowInterval::
instant() {
_node.show();
}
////////////////////////////////////////////////////////////////////
// Function: ShowInterval::reverse_instant
// Access: Published, Virtual
// Description: This is called in lieu of reverse_initialize()
// .. step() .. reverse_finalize(), when everything is
// to happen within one frame. The interval should
// initialize itself, then leave itself in the initial
// state.
////////////////////////////////////////////////////////////////////
void ShowInterval::
reverse_instant() {
_node.hide();
}

View File

@@ -0,0 +1,61 @@
// Filename: showInterval.h
// Created by: drose (27Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef SHOWINTERVAL_H
#define SHOWINTERVAL_H
#include "directbase.h"
#include "cInterval.h"
////////////////////////////////////////////////////////////////////
// Class : ShowInterval
// Description : An interval that calls NodePath::show().
////////////////////////////////////////////////////////////////////
class EXPCL_DIRECT ShowInterval : public CInterval {
PUBLISHED:
ShowInterval(const NodePath &node, const string &name = string());
virtual void instant();
virtual void reverse_instant();
private:
NodePath _node;
static int _unique_index;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CInterval::init_type();
register_type(_type_handle, "ShowInterval",
CInterval::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "showInterval.I"
#endif