mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
define ivalMgr
This commit is contained in:
parent
707fd440c9
commit
24f194bd45
@ -5,59 +5,17 @@
|
||||
"""
|
||||
|
||||
def setT(self, t):
|
||||
t = min(max(t, 0.0), self.getDuration())
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInitialize(t)
|
||||
elif state == CInterval.SFinal:
|
||||
self.privReverseInitialize(t)
|
||||
else:
|
||||
self.privStep(t)
|
||||
# Overridden from the C++ function to call privPostEvent
|
||||
# afterward. We do this by renaming the C++ function in
|
||||
# FFIRename.
|
||||
self.__cSetT(t)
|
||||
self.privPostEvent()
|
||||
|
||||
def start(self, t0 = 0.0, duration = None, scale = 1.0):
|
||||
if self.isPlaying():
|
||||
self.finish()
|
||||
def play(self, t0 = 0.0, duration = None, scale = 1.0):
|
||||
if duration: # None or 0 implies full length
|
||||
self.setupPlay(t0, t0 + duration, scale)
|
||||
self.start(t0, t0 + duration, scale)
|
||||
else:
|
||||
self.setupPlay(t0, -1, scale)
|
||||
self.privPostEvent()
|
||||
self.__loop = 0
|
||||
self.__spawnTask()
|
||||
|
||||
def loop(self, t0 = 0.0, duration = None, scale = 1.0):
|
||||
self.start(t0, duration, scale)
|
||||
self.__loop = 1
|
||||
return
|
||||
|
||||
def pause(self):
|
||||
if self.getState() == CInterval.SStarted:
|
||||
self.privInterrupt()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
return self.getT()
|
||||
|
||||
def resume(self, t0 = None):
|
||||
if not hasattr(self, "_CInterval__loop"):
|
||||
self.__loop = 0
|
||||
if t0 != None:
|
||||
self.setT(t0)
|
||||
self.setupResume()
|
||||
if not self.isPlaying():
|
||||
self.__spawnTask()
|
||||
|
||||
def finish(self):
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInstant()
|
||||
elif state != CInterval.SFinal:
|
||||
self.privFinalize()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
|
||||
def play(self, *args, **kw):
|
||||
self.start(*args, **kw)
|
||||
self.start(t0, -1, scale)
|
||||
|
||||
def stop(self):
|
||||
self.finish()
|
||||
@ -65,9 +23,6 @@
|
||||
def setFinalT(self):
|
||||
self.finish()
|
||||
|
||||
def isPlaying(self):
|
||||
return taskMgr.hasTaskNamed(self.getName() + '-play')
|
||||
|
||||
def privPostEvent(self):
|
||||
# Call after calling any of the priv* methods to do any required
|
||||
# Python finishing steps.
|
||||
@ -76,32 +31,6 @@
|
||||
for func in self.setTHooks:
|
||||
func(t)
|
||||
|
||||
def __spawnTask(self):
|
||||
# Spawn task
|
||||
import Task
|
||||
taskName = self.getName() + '-play'
|
||||
task = Task.Task(self.__playTask)
|
||||
task.interval = self
|
||||
taskMgr.add(task, taskName)
|
||||
|
||||
def __removeTask(self):
|
||||
# Kill old task(s), including those from a similarly-named but
|
||||
# different interval.
|
||||
taskName = self.getName() + '-play'
|
||||
oldTasks = taskMgr.getTasksNamed(taskName)
|
||||
for task in oldTasks:
|
||||
if hasattr(task, "interval"):
|
||||
taskMgr.remove(task)
|
||||
|
||||
def __playTask(self, task):
|
||||
import Task
|
||||
loopCount = self.stepPlay()
|
||||
self.privPostEvent()
|
||||
if loopCount == 0 or self.__loop:
|
||||
return Task.cont
|
||||
else:
|
||||
return Task.done
|
||||
|
||||
def popupControls(self, tl = None):
|
||||
""" popupControls()
|
||||
Popup control panel for interval.
|
||||
|
@ -44,6 +44,7 @@ methodRenameDictionary = {
|
||||
'operator<<=' : '__ilshift__',
|
||||
'operator>>=' : '__irshift__',
|
||||
'print' : 'Cprint',
|
||||
'CInterval.setT' : '__cSetT',
|
||||
}
|
||||
|
||||
classRenameDictionary = {
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""ActorInterval module: contains the ActorInterval class"""
|
||||
|
||||
from PandaModules import *
|
||||
from DirectNotifyGlobal import *
|
||||
import Interval
|
||||
import math
|
||||
import LerpBlendHelpers
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from PandaModules import *
|
||||
from MessengerGlobal import *
|
||||
from DirectNotifyGlobal import *
|
||||
import Interval
|
||||
import types
|
||||
|
||||
|
@ -27,13 +27,14 @@ class Interval(DirectObject):
|
||||
self.__startTAtStart = 1
|
||||
self.__endT = duration
|
||||
self.__endTAtEnd = 1
|
||||
self.__playRate = 1.0
|
||||
self.__doLoop = 0
|
||||
self.__loopCount = 0
|
||||
|
||||
# Set true if the interval should be invoked if it was
|
||||
# completely skipped over during initialize or finalize, false
|
||||
# if it should be ignored in this case.
|
||||
self.openEnded = openEnded
|
||||
|
||||
self.__loop = 0
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
@ -53,10 +54,55 @@ class Interval(DirectObject):
|
||||
# finish().
|
||||
return (self.getState() == CInterval.SInitial or \
|
||||
self.getState() == CInterval.SFinal)
|
||||
|
||||
def setT(self, t):
|
||||
t = min(max(t, 0.0), self.getDuration())
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInitialize(t)
|
||||
elif state == CInterval.SFinal:
|
||||
self.privReverseInitialize(t)
|
||||
else:
|
||||
self.privStep(t)
|
||||
self.privPostEvent()
|
||||
|
||||
def getT(self):
|
||||
return self.currT
|
||||
|
||||
def start(self, startT = 0.0, endT = -1.0, playRate = 1.0):
|
||||
self.setupPlay(startT, endT, playRate, 0)
|
||||
self.__spawnTask()
|
||||
|
||||
def loop(self, startT = 0.0, endT = -1.0, playRate = 1.0):
|
||||
self.setupPlay(startT, endT, playRate, 1)
|
||||
self.__spawnTask()
|
||||
|
||||
def pause(self):
|
||||
if self.getState() == CInterval.SStarted:
|
||||
self.privInterrupt()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
return self.getT()
|
||||
|
||||
def resume(self, t0 = None):
|
||||
if t0 != None:
|
||||
self.setT(t0)
|
||||
self.setupResume()
|
||||
if not self.isPlaying():
|
||||
self.__spawnTask()
|
||||
|
||||
def finish(self):
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInstant()
|
||||
elif state != CInterval.SFinal:
|
||||
self.privFinalize()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
|
||||
def isPlaying(self):
|
||||
return taskMgr.hasTaskNamed(self.getName() + '-play')
|
||||
|
||||
def setDoneEvent(self, event):
|
||||
self.doneEvent = event
|
||||
|
||||
@ -133,7 +179,7 @@ class Interval(DirectObject):
|
||||
if self.doneEvent:
|
||||
messenger.throw(self.doneEvent)
|
||||
|
||||
def setupPlay(self, startT, endT, playRate):
|
||||
def setupPlay(self, startT, endT, playRate, doLoop):
|
||||
duration = self.getDuration()
|
||||
|
||||
if startT <= 0:
|
||||
@ -155,6 +201,7 @@ class Interval(DirectObject):
|
||||
|
||||
self.__clockStart = globalClock.getFrameTime()
|
||||
self.__playRate = playRate
|
||||
self.__doLoop = doLoop
|
||||
self.__loopCount = 0
|
||||
|
||||
def setupResume(self):
|
||||
@ -178,7 +225,7 @@ class Interval(DirectObject):
|
||||
if self.isStopped():
|
||||
self.privInitialize(t)
|
||||
else:
|
||||
self.prevStep(t)
|
||||
self.privStep(t)
|
||||
|
||||
else:
|
||||
# Past the ending point; time to finalize.
|
||||
@ -214,6 +261,8 @@ class Interval(DirectObject):
|
||||
# Not supported at the moment.
|
||||
pass
|
||||
|
||||
return (self.__loopCount == 0 or self.__doLoop)
|
||||
|
||||
def __repr__(self, indent=0):
|
||||
""" __repr__(indent)
|
||||
"""
|
||||
@ -226,58 +275,6 @@ class Interval(DirectObject):
|
||||
# The rest of these methods are duplicates of functions defined
|
||||
# for the CInterval class via the file CInterval-extensions.py.
|
||||
|
||||
def setT(self, t):
|
||||
t = min(max(t, 0.0), self.getDuration())
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInitialize(t)
|
||||
elif state == CInterval.SFinal:
|
||||
self.privReverseInitialize(t)
|
||||
else:
|
||||
self.privStep(t)
|
||||
self.privPostEvent()
|
||||
|
||||
def start(self, t0 = 0.0, duration = None, scale = 1.0):
|
||||
if self.isPlaying():
|
||||
self.finish()
|
||||
if duration: # None or 0 implies full length
|
||||
self.setupPlay(t0, t0 + duration, scale)
|
||||
else:
|
||||
self.setupPlay(t0, -1, scale)
|
||||
self.privPostEvent()
|
||||
self.__loop = 0
|
||||
self.__spawnTask()
|
||||
|
||||
def loop(self, t0 = 0.0, duration = None, scale = 1.0):
|
||||
self.start(t0, duration, scale)
|
||||
self.__loop = 1
|
||||
return
|
||||
|
||||
def pause(self):
|
||||
if self.getState() == CInterval.SStarted:
|
||||
self.privInterrupt()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
return self.getT()
|
||||
|
||||
def resume(self, t0 = None):
|
||||
if not hasattr(self, "_CInterval__loop"):
|
||||
self.__loop = 0
|
||||
if t0 != None:
|
||||
self.setT(t0)
|
||||
self.setupResume()
|
||||
if not self.isPlaying():
|
||||
self.__spawnTask()
|
||||
|
||||
def finish(self):
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInstant()
|
||||
elif state != CInterval.SFinal:
|
||||
self.privFinalize()
|
||||
self.privPostEvent()
|
||||
self.__removeTask()
|
||||
|
||||
def play(self, *args, **kw):
|
||||
self.start(*args, **kw)
|
||||
|
||||
@ -287,9 +284,6 @@ class Interval(DirectObject):
|
||||
def setFinalT(self):
|
||||
self.finish()
|
||||
|
||||
def isPlaying(self):
|
||||
return taskMgr.hasTaskNamed(self.getName() + '-play')
|
||||
|
||||
def privPostEvent(self):
|
||||
# Call after calling any of the priv* methods to do any required
|
||||
# Python finishing steps.
|
||||
@ -301,6 +295,7 @@ class Interval(DirectObject):
|
||||
def __spawnTask(self):
|
||||
# Spawn task
|
||||
import Task
|
||||
self.__removeTask()
|
||||
taskName = self.getName() + '-play'
|
||||
task = Task.Task(self.__playTask)
|
||||
task.interval = self
|
||||
@ -318,9 +313,9 @@ class Interval(DirectObject):
|
||||
|
||||
def __playTask(self, task):
|
||||
import Task
|
||||
loopCount = self.stepPlay()
|
||||
again = self.stepPlay()
|
||||
self.privPostEvent()
|
||||
if loopCount == 0 or self.__loop:
|
||||
if again:
|
||||
return Task.cont
|
||||
else:
|
||||
return Task.done
|
||||
|
@ -10,3 +10,4 @@ from ParticleInterval import *
|
||||
from SoundInterval import *
|
||||
from WaitInterval import *
|
||||
from MetaInterval import *
|
||||
from IntervalManager import *
|
||||
|
@ -1,5 +1,6 @@
|
||||
from PandaModules import *
|
||||
from DirectNotifyGlobal import *
|
||||
from IntervalManager import ivalMgr
|
||||
import Interval
|
||||
import Task
|
||||
import types
|
||||
@ -31,6 +32,11 @@ class MetaInterval(CMetaInterval):
|
||||
name = kw['name']
|
||||
del kw['name']
|
||||
|
||||
interruptible = 0
|
||||
if kw.has_key('interruptible'):
|
||||
interruptible = kw['interruptible']
|
||||
del kw['interruptible']
|
||||
|
||||
if kw:
|
||||
self.notify.error("Unexpected keyword parameters: %s" % (kw.keys()))
|
||||
|
||||
@ -50,6 +56,8 @@ class MetaInterval(CMetaInterval):
|
||||
MetaInterval.SequenceNum += 1
|
||||
|
||||
CMetaInterval.__init__(self, name)
|
||||
self.__manager = ivalMgr
|
||||
self.setInterruptible(interruptible)
|
||||
|
||||
self.pythonIvals = []
|
||||
|
||||
@ -113,6 +121,7 @@ class MetaInterval(CMetaInterval):
|
||||
self.__ivalsDirty = 1
|
||||
return self
|
||||
|
||||
# Functions to define sequence, parallel, and track behaviors:
|
||||
|
||||
def addSequence(self, list, relTime, relTo):
|
||||
# Adds the given list of intervals to the MetaInterval to be
|
||||
@ -208,7 +217,53 @@ class MetaInterval(CMetaInterval):
|
||||
|
||||
else:
|
||||
self.notify.error("Not an Interval: %s" % (ival,))
|
||||
|
||||
|
||||
# Functions to support automatic playback of MetaIntervals along
|
||||
# with all of their associated Python callbacks:
|
||||
|
||||
def setManager(self, manager):
|
||||
self.__manager = manager
|
||||
CMetaInterval.setManager(self, manager)
|
||||
|
||||
def getManager(self):
|
||||
return self.__manager
|
||||
|
||||
def start(self, startT = 0.0, endT = -1.0, playRate = 1.0):
|
||||
self.__updateIvals()
|
||||
self.setupPlay(startT, endT, playRate, 0)
|
||||
self.__manager.addInterval(self)
|
||||
|
||||
def loop(self, startT = 0.0, endT = -1.0, playRate = 1.0):
|
||||
self.__updateIvals()
|
||||
self.setupPlay(startT, endT, playRate, 1)
|
||||
self.__manager.addInterval(self)
|
||||
|
||||
def pause(self):
|
||||
if self.getState() == CInterval.SStarted:
|
||||
self.privInterrupt()
|
||||
self.__manager.removeInterval(self)
|
||||
self.privPostEvent()
|
||||
return self.getT()
|
||||
|
||||
def resume(self, t0 = None):
|
||||
self.__updateIvals()
|
||||
if t0 != None:
|
||||
self.setT(t0)
|
||||
self.setupResume()
|
||||
self.__manager.addInterval(self)
|
||||
|
||||
def finish(self):
|
||||
state = self.getState()
|
||||
if state == CInterval.SInitial:
|
||||
self.privInstant()
|
||||
elif state != CInterval.SFinal:
|
||||
self.privFinalize()
|
||||
self.__manager.removeInterval(self)
|
||||
self.privPostEvent()
|
||||
|
||||
|
||||
|
||||
# Internal functions:
|
||||
|
||||
def __updateIvals(self):
|
||||
# The MetaInterval object does not create the C++ list of
|
||||
@ -312,20 +367,6 @@ class MetaInterval(CMetaInterval):
|
||||
self.__updateIvals()
|
||||
return CMetaInterval.getDuration(self)
|
||||
|
||||
def start(self, *args, **kw):
|
||||
# This function overrides from the parent level to force it to
|
||||
# update the interval list first, if necessary.
|
||||
|
||||
self.__updateIvals()
|
||||
return CMetaInterval.start(self, *args, **kw)
|
||||
|
||||
def loop(self, *args, **kw):
|
||||
# This function overrides from the parent level to force it to
|
||||
# update the interval list first, if necessary.
|
||||
|
||||
self.__updateIvals()
|
||||
return CMetaInterval.loop(self, *args, **kw)
|
||||
|
||||
def __repr__(self, *args, **kw):
|
||||
# This function overrides from the parent level to force it to
|
||||
# update the interval list first, if necessary.
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import Interval
|
||||
from PandaModules import *
|
||||
from DirectNotifyGlobal import *
|
||||
|
||||
# import Mopath
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""ParticleInterval module: contains the ParticleInterval class"""
|
||||
|
||||
from PandaModules import *
|
||||
from DirectNotifyGlobal import *
|
||||
import Interval
|
||||
|
||||
import ParticleEffect
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""SoundInterval module: contains the SoundInterval class"""
|
||||
|
||||
from PandaModules import *
|
||||
from DirectNotifyGlobal import *
|
||||
import Interval
|
||||
|
||||
class SoundInterval(Interval.Interval):
|
||||
@ -61,6 +62,9 @@ class SoundInterval(Interval.Interval):
|
||||
def privStep(self, t):
|
||||
if self.state == CInterval.SPaused:
|
||||
# Restarting from a pause.
|
||||
self.sound.setVolume(self.volume)
|
||||
self.sound.setTime(t)
|
||||
self.sound.setLoop(self.loop)
|
||||
self.sound.play()
|
||||
self.state = CInterval.SStarted
|
||||
self.currT = t
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define SOURCES \
|
||||
config_interval.cxx config_interval.h \
|
||||
cInterval.cxx cInterval.I cInterval.h \
|
||||
cIntervalManager.cxx cIntervalManager.I cIntervalManager.h \
|
||||
cLerpInterval.cxx cLerpInterval.I cLerpInterval.h \
|
||||
cLerpNodePathInterval.cxx cLerpNodePathInterval.I cLerpNodePathInterval.h \
|
||||
cLerpAnimEffectInterval.cxx cLerpAnimEffectInterval.I cLerpAnimEffectInterval.h \
|
||||
|
@ -78,18 +78,6 @@ is_stopped() const {
|
||||
return (_state == S_initial || _state == S_final);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::get_t
|
||||
// Access: Published
|
||||
// Description: Returns the current time of the interval: the last
|
||||
// value of t passed to priv_initialize(), priv_step(), or
|
||||
// priv_finalize().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double CInterval::
|
||||
get_t() const {
|
||||
return _curr_t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::set_done_event
|
||||
// Access: Published
|
||||
@ -116,6 +104,74 @@ get_done_event() const {
|
||||
return _done_event;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::get_t
|
||||
// Access: Published
|
||||
// Description: Returns the current time of the interval: the last
|
||||
// value of t passed to priv_initialize(), priv_step(), or
|
||||
// priv_finalize().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double CInterval::
|
||||
get_t() const {
|
||||
return _curr_t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::set_interruptible
|
||||
// Access: Published
|
||||
// Description: Changes the state of the 'interruptible' flag. If
|
||||
// this is true, the interval may be arbitrarily
|
||||
// interrupted when the system needs to reset due to
|
||||
// some external event by calling
|
||||
// CIntervalManager::pause_all_interruptible(). If this
|
||||
// is false (the default), the interval must always be
|
||||
// explicitly finished or paused.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CInterval::
|
||||
set_interruptible(bool interruptible) {
|
||||
_interruptible = interruptible;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::get_interruptible
|
||||
// Access: Published
|
||||
// Description: Returns the state of the 'interruptible' flag. See
|
||||
// set_interruptible().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool CInterval::
|
||||
get_interruptible() const {
|
||||
return _interruptible;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::set_manager
|
||||
// Access: Published
|
||||
// Description: Indicates the CIntervalManager object which will be
|
||||
// responsible for playing this interval. This defaults
|
||||
// to the global CIntervalManager; you should need to
|
||||
// change this only if you have special requirements for
|
||||
// playing this interval.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CInterval::
|
||||
set_manager(CIntervalManager *manager) {
|
||||
_manager = manager;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::get_manager
|
||||
// Access: Published
|
||||
// Description: Returns the CIntervalManager object which will be
|
||||
// responsible for playing this interval. Note that
|
||||
// this can only return a C++ object; if the particular
|
||||
// CIntervalManager object has been extended in the
|
||||
// scripting language, this will return the encapsulated
|
||||
// C++ object, not the full extended object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CIntervalManager *CInterval::
|
||||
get_manager() const {
|
||||
return _manager;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::recompute
|
||||
// Access: Protected
|
||||
|
@ -17,6 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cInterval.h"
|
||||
#include "cIntervalManager.h"
|
||||
#include "indent.h"
|
||||
#include "clockObject.h"
|
||||
#include "throw_event.h"
|
||||
@ -38,198 +39,157 @@ CInterval(const string &name, double duration, bool open_ended) :
|
||||
_open_ended(open_ended),
|
||||
_dirty(false)
|
||||
{
|
||||
_interruptible = false;
|
||||
_manager = CIntervalManager::get_global_ptr();
|
||||
_clock_start = 0.0;
|
||||
_start_t = 0.0;
|
||||
_end_t = _duration;
|
||||
_start_t_at_start = true;
|
||||
_end_t_at_end = true;
|
||||
_play_rate = 1.0;
|
||||
_do_loop = false;
|
||||
_loop_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::setup_play
|
||||
// Function: CInterval::set_t
|
||||
// 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.
|
||||
// Description: Explicitly sets the time within the interval.
|
||||
// Normally, you would use start() .. finish() to let
|
||||
// the time play normally, but this may be used to set
|
||||
// the time to some particular value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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);
|
||||
set_t(double t) {
|
||||
t = min(max(t, 0.0), get_duration());
|
||||
switch (get_state()) {
|
||||
case S_initial:
|
||||
priv_initialize(t);
|
||||
break;
|
||||
|
||||
double duration = get_duration();
|
||||
case S_final:
|
||||
priv_reverse_initialize(t);
|
||||
break;
|
||||
|
||||
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;
|
||||
default:
|
||||
priv_step(t);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::setup_resume
|
||||
// Function: CInterval::start
|
||||
// Access: Published
|
||||
// Description: Called to prepare the interval for restarting at the
|
||||
// current point within the interval after an
|
||||
// interruption.
|
||||
// Description: Starts the interval playing by registering it with
|
||||
// the current CIntervalManager. The interval will
|
||||
// play to the end and stop.
|
||||
//
|
||||
// If end_t is less than zero, it indicates the end of
|
||||
// the interval.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CInterval::
|
||||
setup_resume() {
|
||||
double now = ClockObject::get_global_clock()->get_frame_time();
|
||||
if (_play_rate > 0.0) {
|
||||
_clock_start = now - ((get_t() - _start_t) / _play_rate);
|
||||
|
||||
} else if (_play_rate < 0.0) {
|
||||
_clock_start = now - ((get_t() - _end_t) / _play_rate);
|
||||
}
|
||||
_loop_count = 0;
|
||||
start(double start_t, double end_t, double play_rate) {
|
||||
setup_play(start_t, end_t, play_rate, false);
|
||||
_manager->add_c_interval(this, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::step_play
|
||||
// Function: CInterval::loop
|
||||
// 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.
|
||||
// Description: Starts the interval playing by registering it with
|
||||
// the current CIntervalManager. The interval will
|
||||
// play until it is interrupted with finish() or
|
||||
// pause(), looping back to start_t when it reaches
|
||||
// end_t.
|
||||
//
|
||||
// If end_t is less than zero, it indicates the end of
|
||||
// the interval.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CInterval::
|
||||
step_play() {
|
||||
double now = ClockObject::get_global_clock()->get_frame_time();
|
||||
void CInterval::
|
||||
loop(double start_t, double end_t, double play_rate) {
|
||||
setup_play(start_t, end_t, play_rate, true);
|
||||
_manager->add_c_interval(this, false);
|
||||
}
|
||||
|
||||
if (_play_rate >= 0.0) {
|
||||
double t = (now - _clock_start) * _play_rate + _start_t;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::pause
|
||||
// Access: Published
|
||||
// Description: Stops the interval from playing but leaves it in its
|
||||
// current state. It may later be resumed from this
|
||||
// point by calling resume().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
double CInterval::
|
||||
pause() {
|
||||
if (get_state() == S_started) {
|
||||
priv_interrupt();
|
||||
}
|
||||
int index = _manager->find_c_interval(this->get_name());
|
||||
if (index >= 0) {
|
||||
_manager->remove_c_interval(index);
|
||||
}
|
||||
return get_t();
|
||||
}
|
||||
|
||||
if (_end_t_at_end) {
|
||||
_end_t = get_duration();
|
||||
}
|
||||
|
||||
if (t < _end_t) {
|
||||
// In the middle of the interval, not a problem.
|
||||
if (is_stopped()) {
|
||||
priv_initialize(t);
|
||||
} else {
|
||||
priv_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 (is_stopped()) {
|
||||
if (get_open_ended() || _loop_count != 0) {
|
||||
priv_instant();
|
||||
}
|
||||
} else {
|
||||
priv_finalize();
|
||||
}
|
||||
} else {
|
||||
if (is_stopped()) {
|
||||
priv_initialize(_end_t);
|
||||
} else {
|
||||
priv_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;
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::resume
|
||||
// Access: Published
|
||||
// Description: Restarts the interval from its current point after a
|
||||
// previous call to pause().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CInterval::
|
||||
resume() {
|
||||
setup_resume();
|
||||
_manager->add_c_interval(this, false);
|
||||
}
|
||||
|
||||
} 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 (is_stopped()) {
|
||||
priv_reverse_initialize(t);
|
||||
} else {
|
||||
priv_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 (is_stopped()) {
|
||||
if (get_open_ended() || _loop_count != 0) {
|
||||
priv_reverse_instant();
|
||||
}
|
||||
} else {
|
||||
priv_reverse_finalize();
|
||||
}
|
||||
} else {
|
||||
if (is_stopped()) {
|
||||
priv_reverse_initialize(_start_t);
|
||||
} else {
|
||||
priv_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;
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::resume
|
||||
// Access: Published
|
||||
// Description: Restarts the interval from the indicated point after a
|
||||
// previous call to pause().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CInterval::
|
||||
resume(double start_t) {
|
||||
set_t(start_t);
|
||||
setup_resume();
|
||||
_manager->add_c_interval(this, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::finish
|
||||
// Access: Published
|
||||
// Description: Stops the interval from playing and sets it to its
|
||||
// final state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CInterval::
|
||||
finish() {
|
||||
switch (get_state()) {
|
||||
case S_initial:
|
||||
priv_instant();
|
||||
break;
|
||||
|
||||
case S_final:
|
||||
break;
|
||||
|
||||
default:
|
||||
priv_finalize();
|
||||
}
|
||||
|
||||
return _loop_count;
|
||||
int index = _manager->find_c_interval(this->get_name());
|
||||
if (index >= 0) {
|
||||
_manager->remove_c_interval(index);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::is_playing
|
||||
// Access: Published
|
||||
// Description: Returns true if the interval is currently playing,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CInterval::
|
||||
is_playing() const {
|
||||
int index = _manager->find_c_interval(this->get_name());
|
||||
return (index >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -434,6 +394,192 @@ write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level) << *this << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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, bool do_loop) {
|
||||
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;
|
||||
_do_loop = do_loop;
|
||||
_loop_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::setup_resume
|
||||
// Access: Published
|
||||
// Description: Called to prepare the interval for restarting at the
|
||||
// current point within the interval after an
|
||||
// interruption.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CInterval::
|
||||
setup_resume() {
|
||||
double now = ClockObject::get_global_clock()->get_frame_time();
|
||||
if (_play_rate > 0.0) {
|
||||
_clock_start = now - ((get_t() - _start_t) / _play_rate);
|
||||
|
||||
} else if (_play_rate < 0.0) {
|
||||
_clock_start = now - ((get_t() - _end_t) / _play_rate);
|
||||
}
|
||||
_loop_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::step_play
|
||||
// Access: Published
|
||||
// Description: Should be called once per frame to execute the
|
||||
// automatic timed playback begun with setup_play().
|
||||
//
|
||||
// Returns true if the interval should continue, false
|
||||
// if it is done and should stop.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool 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 (_end_t_at_end) {
|
||||
_end_t = get_duration();
|
||||
}
|
||||
|
||||
if (t < _end_t) {
|
||||
// In the middle of the interval, not a problem.
|
||||
if (is_stopped()) {
|
||||
priv_initialize(t);
|
||||
} else {
|
||||
priv_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 (is_stopped()) {
|
||||
if (get_open_ended() || _loop_count != 0) {
|
||||
priv_instant();
|
||||
}
|
||||
} else {
|
||||
priv_finalize();
|
||||
}
|
||||
} else {
|
||||
if (is_stopped()) {
|
||||
priv_initialize(_end_t);
|
||||
} else {
|
||||
priv_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 (is_stopped()) {
|
||||
priv_reverse_initialize(t);
|
||||
} else {
|
||||
priv_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 (is_stopped()) {
|
||||
if (get_open_ended() || _loop_count != 0) {
|
||||
priv_reverse_instant();
|
||||
}
|
||||
} else {
|
||||
priv_reverse_finalize();
|
||||
}
|
||||
} else {
|
||||
if (is_stopped()) {
|
||||
priv_reverse_initialize(_start_t);
|
||||
} else {
|
||||
priv_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 == 0 || _do_loop);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CInterval::mark_dirty
|
||||
// Access: Public
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "pvector.h"
|
||||
#include "config_interval.h"
|
||||
|
||||
class CIntervalManager;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CInterval
|
||||
// Description : The base class for timeline components. A CInterval
|
||||
@ -66,14 +68,26 @@ PUBLISHED:
|
||||
|
||||
INLINE State get_state() const;
|
||||
INLINE bool is_stopped() const;
|
||||
INLINE double get_t() const;
|
||||
|
||||
INLINE void set_done_event(const string &event);
|
||||
INLINE const string &get_done_event() const;
|
||||
|
||||
void setup_play(double start_time, double end_time, double play_rate);
|
||||
void setup_resume();
|
||||
int step_play();
|
||||
void set_t(double t);
|
||||
INLINE double get_t() const;
|
||||
|
||||
INLINE void set_interruptible(bool interruptible);
|
||||
INLINE bool get_interruptible() const;
|
||||
|
||||
INLINE void set_manager(CIntervalManager *manager);
|
||||
INLINE CIntervalManager *get_manager() const;
|
||||
|
||||
void start(double start_t = 0.0, double end_t = -1.0, double play_rate = 1.0);
|
||||
void loop(double start_t = 0.0, double end_t = -1.0, double play_rate = 1.0);
|
||||
double pause();
|
||||
void resume();
|
||||
void resume(double start_t);
|
||||
void finish();
|
||||
bool is_playing() const;
|
||||
|
||||
// These functions control the actual playback of the interval.
|
||||
// Don't call them directly; they're intended to be called from a
|
||||
@ -96,6 +110,11 @@ PUBLISHED:
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
void setup_play(double start_time, double end_time, double play_rate,
|
||||
bool do_loop);
|
||||
void setup_resume();
|
||||
bool step_play();
|
||||
|
||||
public:
|
||||
void mark_dirty();
|
||||
|
||||
@ -113,6 +132,9 @@ protected:
|
||||
string _done_event;
|
||||
double _duration;
|
||||
|
||||
bool _interruptible;
|
||||
CIntervalManager *_manager;
|
||||
|
||||
// For setup_play() and step_play().
|
||||
double _clock_start;
|
||||
double _start_t;
|
||||
@ -120,8 +142,9 @@ protected:
|
||||
bool _end_t_at_end;
|
||||
bool _start_t_at_start;
|
||||
double _play_rate;
|
||||
bool _do_loop;
|
||||
int _loop_count;
|
||||
|
||||
|
||||
private:
|
||||
bool _open_ended;
|
||||
bool _dirty;
|
||||
|
25
direct/src/interval/cIntervalManager.I
Normal file
25
direct/src/interval/cIntervalManager.I
Normal file
@ -0,0 +1,25 @@
|
||||
// Filename: cIntervalManager.I
|
||||
// Created by: drose (10Sep02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const CIntervalManager &ival_mgr) {
|
||||
ival_mgr.output(out);
|
||||
return out;
|
||||
}
|
||||
|
417
direct/src/interval/cIntervalManager.cxx
Normal file
417
direct/src/interval/cIntervalManager.cxx
Normal file
@ -0,0 +1,417 @@
|
||||
// Filename: cIntervalManager.cxx
|
||||
// Created by: drose (10Sep02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "cIntervalManager.h"
|
||||
#include "cMetaInterval.h"
|
||||
#include "dcast.h"
|
||||
|
||||
CIntervalManager *CIntervalManager::_global_ptr;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CIntervalManager::
|
||||
CIntervalManager() {
|
||||
_first_slot = 0;
|
||||
_next_event_index = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::Destructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CIntervalManager::
|
||||
~CIntervalManager() {
|
||||
nassertv(_name_index.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::add_c_interval
|
||||
// Access: Published
|
||||
// Description: Adds the interval to the manager, and returns a
|
||||
// unique index for the interval. This index will be
|
||||
// unique among all the currently added intervals, but
|
||||
// not unique across all intervals ever added to the
|
||||
// manager. The maximum index value will never exceed
|
||||
// the maximum number of intervals added at any given
|
||||
// time.
|
||||
//
|
||||
// If the external flag is true, the interval is
|
||||
// understood to also be stored in the scripting
|
||||
// language data structures. In this case, it will be
|
||||
// available for information returned by
|
||||
// get_next_event() and get_next_removal(). If external
|
||||
// is false, the interval's index will never be returned
|
||||
// by these two functions.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
add_c_interval(CInterval *interval, bool external) {
|
||||
// First, check the name index. If we already have an interval by
|
||||
// this name, it gets finished and removed.
|
||||
NameIndex::iterator ni = _name_index.find(interval->get_name());
|
||||
if (ni != _name_index.end()) {
|
||||
int old_index = (*ni).second;
|
||||
nassertr(old_index >= 0 && old_index < (int)_intervals.size(), -1)
|
||||
CInterval *old_interval = _intervals[old_index]._interval;
|
||||
if (old_interval == interval) {
|
||||
// No, it's the same interval that was already here. In this
|
||||
// case, don't finish the interval; just return it.
|
||||
return old_index;
|
||||
}
|
||||
finish_interval(old_interval);
|
||||
remove_index(old_index);
|
||||
_name_index.erase(ni);
|
||||
}
|
||||
|
||||
int slot;
|
||||
|
||||
if (_first_slot >= (int)_intervals.size()) {
|
||||
// All the slots are filled; make a new slot.
|
||||
nassertr(_first_slot == (int)_intervals.size(), -1);
|
||||
slot = (int)_intervals.size();
|
||||
_intervals.push_back(IntervalDef());
|
||||
_first_slot = (int)_intervals.size();
|
||||
|
||||
} else {
|
||||
// Some slot is available; use it.
|
||||
slot = _first_slot;
|
||||
nassertr(slot >= 0 && slot < (int)_intervals.size(), -1);
|
||||
_first_slot = _intervals[slot]._next_slot;
|
||||
}
|
||||
|
||||
IntervalDef &def = _intervals[slot];
|
||||
def._interval = interval;
|
||||
def._flags = 0;
|
||||
if (external) {
|
||||
def._flags |= F_external;
|
||||
}
|
||||
if (interval->is_of_type(CMetaInterval::get_class_type())) {
|
||||
def._flags |= F_meta_interval;
|
||||
}
|
||||
def._next_slot = -1;
|
||||
|
||||
_name_index[interval->get_name()] = slot;
|
||||
nassertr(_first_slot >= 0, slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::find_c_interval
|
||||
// Access: Published
|
||||
// Description: Returns the index associated with the named interval,
|
||||
// if there is such an interval, or -1 if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
find_c_interval(const string &name) const {
|
||||
NameIndex::const_iterator ni = _name_index.find(name);
|
||||
if (ni != _name_index.end()) {
|
||||
return (*ni).second;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::get_c_interval
|
||||
// Access: Published
|
||||
// Description: Returns the interval associated with the given index.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CInterval *CIntervalManager::
|
||||
get_c_interval(int index) const {
|
||||
nassertr(index >= 0 && index < (int)_intervals.size(), NULL);
|
||||
return _intervals[index]._interval;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::remove_c_interval
|
||||
// Access: Published
|
||||
// Description: Removes the indicated interval from the queue
|
||||
// immediately. It will not be returned from
|
||||
// get_next_removal(), and none of its pending events,
|
||||
// if any, will be returned by get_next_event().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
remove_c_interval(int index) {
|
||||
nassertv(index >= 0 && index < (int)_intervals.size());
|
||||
IntervalDef &def = _intervals[index];
|
||||
nassertv(def._interval != (CInterval *)NULL);
|
||||
|
||||
NameIndex::iterator ni = _name_index.find(def._interval->get_name());
|
||||
nassertv(ni != _name_index.end());
|
||||
nassertv((*ni).second == index);
|
||||
_name_index.erase(ni);
|
||||
|
||||
def._interval = (CInterval *)NULL;
|
||||
def._next_slot = _first_slot;
|
||||
_first_slot = index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::pause_all_interruptible
|
||||
// Access: Published
|
||||
// Description: Pauses (removes from the active queue) all intervals
|
||||
// tagged as "interruptible". These are intervals that
|
||||
// someone fired up but won't necessarily expect to
|
||||
// clean up; they can be interrupted at will when
|
||||
// necessary.
|
||||
//
|
||||
// Returns the number of intervals affected.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
pause_all_interruptible() {
|
||||
int num_paused = 0;
|
||||
|
||||
NameIndex::iterator ni;
|
||||
ni = _name_index.begin();
|
||||
while (ni != _name_index.end()) {
|
||||
int index = (*ni).second;
|
||||
const IntervalDef &def = _intervals[index];
|
||||
nassertr(def._interval != (CInterval *)NULL, num_paused);
|
||||
if (!def._interval->get_interruptible()) {
|
||||
// This interval may be interrupted.
|
||||
if (def._interval->get_state() == CInterval::S_started) {
|
||||
def._interval->priv_interrupt();
|
||||
}
|
||||
NameIndex::iterator prev;
|
||||
prev = ni;
|
||||
++ni;
|
||||
_name_index.erase(prev);
|
||||
remove_index(index);
|
||||
num_paused++;
|
||||
|
||||
} else {
|
||||
// The interval should remain on the active list.
|
||||
++ni;
|
||||
}
|
||||
}
|
||||
|
||||
return num_paused;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::get_num_intervals
|
||||
// Access: Published
|
||||
// Description: Returns the number of currently active intervals.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
get_num_intervals() const {
|
||||
return _name_index.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::step
|
||||
// Access: Published
|
||||
// Description: This should be called every frame to do the
|
||||
// processing for all the active intervals. It will
|
||||
// call step_play() for each interval that has been
|
||||
// added and that has not yet been removed.
|
||||
//
|
||||
// After each call to step(), the scripting language
|
||||
// should call get_next_event() and get_next_removal()
|
||||
// repeatedly to process all the high-level
|
||||
// (e.g. Python-interval-based) events and to manage the
|
||||
// high-level list of intervals.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
step() {
|
||||
NameIndex::iterator ni;
|
||||
ni = _name_index.begin();
|
||||
while (ni != _name_index.end()) {
|
||||
int index = (*ni).second;
|
||||
const IntervalDef &def = _intervals[index];
|
||||
nassertv(def._interval != (CInterval *)NULL);
|
||||
if (!def._interval->step_play()) {
|
||||
// This interval is finished and wants to be removed from the
|
||||
// active list.
|
||||
NameIndex::iterator prev;
|
||||
prev = ni;
|
||||
++ni;
|
||||
_name_index.erase(prev);
|
||||
remove_index(index);
|
||||
|
||||
} else {
|
||||
// The interval can remain on the active list.
|
||||
++ni;
|
||||
}
|
||||
}
|
||||
|
||||
_next_event_index = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::get_next_event
|
||||
// Access: Published
|
||||
// Description: This should be called by the scripting language after
|
||||
// each call to step(). It returns the index number of
|
||||
// the next interval that has events requiring servicing
|
||||
// by the scripting language, or -1 if no more intervals
|
||||
// have any events pending.
|
||||
//
|
||||
// If this function returns something other than -1, it
|
||||
// is the scripting language's responsibility to query
|
||||
// the indicated interval for its next event via
|
||||
// get_event_index(), and eventually pop_event().
|
||||
//
|
||||
// Then get_next_event() should be called again until it
|
||||
// returns -1.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
get_next_event() {
|
||||
while (_next_event_index < (int)_intervals.size()) {
|
||||
IntervalDef &def = _intervals[_next_event_index];
|
||||
if (def._interval != (CInterval *)NULL &&
|
||||
(def._flags & F_meta_interval) != 0) {
|
||||
CMetaInterval *meta_interval;
|
||||
DCAST_INTO_R(meta_interval, def._interval, -1);
|
||||
if (meta_interval->is_event_ready()) {
|
||||
nassertr((def._flags & F_external) != 0, -1);
|
||||
return _next_event_index;
|
||||
}
|
||||
}
|
||||
_next_event_index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::get_next_removal
|
||||
// Access: Published
|
||||
// Description: This should be called by the scripting language after
|
||||
// each call to step(). It returns the index number of
|
||||
// an interval that was recently removed, or -1 if no
|
||||
// intervals were removed.
|
||||
//
|
||||
// If this returns something other than -1, the
|
||||
// scripting language should clean up its own data
|
||||
// structures accordingly, and then call
|
||||
// get_next_removal() again.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CIntervalManager::
|
||||
get_next_removal() {
|
||||
if (!_removed.empty()) {
|
||||
int index = _removed.back();
|
||||
_removed.pop_back();
|
||||
|
||||
nassertr(index >= 0 && index < (int)_intervals.size(), -1);
|
||||
IntervalDef &def = _intervals[index];
|
||||
def._interval = (CInterval *)NULL;
|
||||
def._next_slot = _first_slot;
|
||||
_first_slot = index;
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
output(ostream &out) const {
|
||||
out << "CIntervalManager, " << (int)_name_index.size() << " intervals.";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
write(ostream &out) const {
|
||||
NameIndex::const_iterator ni;
|
||||
for (ni = _name_index.begin(); ni != _name_index.end(); ++ni) {
|
||||
int index = (*ni).second;
|
||||
nassertv(index >= 0 && index < (int)_intervals.size());
|
||||
const IntervalDef &def = _intervals[index];
|
||||
nassertv(def._interval != (CInterval *)NULL);
|
||||
out << *def._interval << "\n";
|
||||
}
|
||||
|
||||
if (!_removed.empty()) {
|
||||
out << "\nRemoved:\n";
|
||||
Removed::const_iterator ri;
|
||||
for (ri = _removed.begin(); ri != _removed.end(); ++ri) {
|
||||
int index = (*ri);
|
||||
nassertv(index >= 0 && index < (int)_intervals.size());
|
||||
const IntervalDef &def = _intervals[index];
|
||||
nassertv(def._interval != (CInterval *)NULL);
|
||||
out << "(R)" << *def._interval << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::get_global_ptr
|
||||
// Access: Published, Static
|
||||
// Description: Returns the pointer to the one global
|
||||
// CIntervalManager object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CIntervalManager *CIntervalManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == (CIntervalManager *)NULL) {
|
||||
_global_ptr = new CIntervalManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::finish_interval
|
||||
// Access: Private
|
||||
// Description: Explicitly finishes the indicated interval in
|
||||
// preparation for moving it to the removed queue.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
finish_interval(CInterval *interval) {
|
||||
switch (interval->get_state()) {
|
||||
case CInterval::S_initial:
|
||||
interval->priv_instant();
|
||||
break;
|
||||
|
||||
case CInterval::S_final:
|
||||
break;
|
||||
|
||||
default:
|
||||
interval->priv_finalize();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CIntervalManager::remove_index
|
||||
// Access: Private
|
||||
// Description: Removes the indicated index number from the active
|
||||
// list, either by moving it to the removed queue if it
|
||||
// is flagged external, or by simply making the slot
|
||||
// available again if it is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CIntervalManager::
|
||||
remove_index(int index) {
|
||||
nassertv(index >= 0 && index < (int)_intervals.size());
|
||||
IntervalDef &def = _intervals[index];
|
||||
if ((def._flags & F_external) != 0) {
|
||||
_removed.push_back(index);
|
||||
} else {
|
||||
def._interval = (CInterval *)NULL;
|
||||
def._next_slot = _first_slot;
|
||||
_first_slot = index;
|
||||
}
|
||||
}
|
101
direct/src/interval/cIntervalManager.h
Normal file
101
direct/src/interval/cIntervalManager.h
Normal file
@ -0,0 +1,101 @@
|
||||
// Filename: cIntervalManager.h
|
||||
// Created by: drose (10Sep02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 CINTERVALMANAGER_H
|
||||
#define CINTERVALMANAGER_H
|
||||
|
||||
#include "directbase.h"
|
||||
#include "cInterval.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pvector.h"
|
||||
#include "pmap.h"
|
||||
#include "vector_int.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CIntervalManager
|
||||
// Description : This object holds a number of currently-playing
|
||||
// intervals and is responsible for advancing them each
|
||||
// frame as needed.
|
||||
//
|
||||
// There is normally only one IntervalManager object in
|
||||
// the world, and it is the responsibility of the
|
||||
// scripting language to call step() on this object once
|
||||
// each frame, and to then process the events indicated by
|
||||
// get_next_event().
|
||||
//
|
||||
// It is also possible to create multiple
|
||||
// IntervalManager objects for special needs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_DIRECT CIntervalManager {
|
||||
PUBLISHED:
|
||||
CIntervalManager();
|
||||
~CIntervalManager();
|
||||
|
||||
int add_c_interval(CInterval *interval, bool external);
|
||||
int find_c_interval(const string &name) const;
|
||||
|
||||
CInterval *get_c_interval(int index) const;
|
||||
void remove_c_interval(int index);
|
||||
|
||||
int pause_all_interruptible();
|
||||
int get_num_intervals() const;
|
||||
|
||||
void step();
|
||||
int get_next_event();
|
||||
int get_next_removal();
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out) const;
|
||||
|
||||
static CIntervalManager *get_global_ptr();
|
||||
|
||||
private:
|
||||
void finish_interval(CInterval *interval);
|
||||
void remove_index(int index);
|
||||
|
||||
enum Flags {
|
||||
F_external = 0x0001,
|
||||
F_meta_interval = 0x0002,
|
||||
};
|
||||
class IntervalDef {
|
||||
public:
|
||||
PT(CInterval) _interval;
|
||||
int _flags;
|
||||
int _next_slot;
|
||||
};
|
||||
typedef pvector<IntervalDef> Intervals;
|
||||
Intervals _intervals;
|
||||
typedef pmap<string, int> NameIndex;
|
||||
NameIndex _name_index;
|
||||
typedef vector_int Removed;
|
||||
Removed _removed;
|
||||
|
||||
int _first_slot;
|
||||
int _next_event_index;
|
||||
|
||||
static CIntervalManager *_global_ptr;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const CInterval &ival_mgr);
|
||||
|
||||
#include "cIntervalManager.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -444,6 +444,14 @@ priv_step(double t) {
|
||||
check_started("priv_step");
|
||||
int now = double_to_int_time(t);
|
||||
|
||||
// One special case: if we step to t == 0.0, it really means to the
|
||||
// very beginning of the interval, *before* any events that occurred
|
||||
// at time 0. (Most of the time, stepping to a particular time
|
||||
// means *after* any events that occurred at that time.)
|
||||
if (t == 0.0) {
|
||||
now = -1;
|
||||
}
|
||||
|
||||
// Now look for events between the last time we ran and the current
|
||||
// time.
|
||||
|
||||
|
@ -12,6 +12,7 @@ from EventManagerGlobal import *
|
||||
from PythonUtil import *
|
||||
from ParticleManagerGlobal import *
|
||||
from PhysicsManagerGlobal import *
|
||||
from IntervalManager import ivalMgr
|
||||
|
||||
import Task
|
||||
import EventManager
|
||||
@ -543,6 +544,11 @@ class ShowBase:
|
||||
self.dgTrav.traverse(self.dataRootNode)
|
||||
return Task.cont
|
||||
|
||||
def ivalloop(self, state):
|
||||
# Execute all intervals in the global ivalMgr.
|
||||
ivalMgr.step()
|
||||
return Task.cont
|
||||
|
||||
def igloop(self, state):
|
||||
# run the collision traversal if we have a
|
||||
# CollisionTraverser set.
|
||||
@ -567,11 +573,15 @@ class ShowBase:
|
||||
# give the dataloop task a reasonably "early" priority,
|
||||
# so that it will get run before most tasks
|
||||
self.taskMgr.add(self.dataloop, 'dataloop', priority = -50)
|
||||
# spawn the ivalloop with a later priority, so that it will
|
||||
# run after most tasks, but before igloop.
|
||||
self.taskMgr.add(self.ivalloop, 'ivalloop', priority = 10)
|
||||
self.eventMgr.restart()
|
||||
|
||||
def shutdown(self):
|
||||
self.taskMgr.remove('igloop')
|
||||
self.taskMgr.remove('dataloop')
|
||||
self.taskMgr.remove('ivalloop')
|
||||
self.eventMgr.shutdown()
|
||||
|
||||
def getBackgroundColor(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user