FunctionInterval.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. """FunctionInterval module: contains the FunctionInterval class"""
  2. __all__ = ['FunctionInterval', 'EventInterval', 'AcceptInterval', 'IgnoreInterval', 'ParentInterval', 'WrtParentInterval', 'PosInterval', 'HprInterval', 'ScaleInterval', 'PosHprInterval', 'HprScaleInterval', 'PosHprScaleInterval', 'Func', 'Wait']
  3. from panda3d.core import *
  4. from panda3d.direct import *
  5. from direct.showbase.MessengerGlobal import *
  6. from direct.directnotify.DirectNotifyGlobal import directNotify
  7. from . import Interval
  8. import sys
  9. #############################################################
  10. ### ###
  11. ### See examples of function intervals in IntervalTest.py ###
  12. ### ###
  13. #############################################################
  14. class FunctionInterval(Interval.Interval):
  15. # Name counter
  16. functionIntervalNum = 1
  17. # Keep a list of function intervals currently in memory for
  18. # Control-C-Control-V redefining. These are just weakrefs so they
  19. # should not cause any leaks.
  20. if __debug__:
  21. import weakref
  22. FunctionIntervals = weakref.WeakKeyDictionary()
  23. @classmethod
  24. def replaceMethod(self, oldFunction, newFunction):
  25. import types
  26. count = 0
  27. for ival in self.FunctionIntervals:
  28. # print 'testing: ', ival.function, oldFunction
  29. # Note: you can only replace methods currently
  30. if type(ival.function) == types.MethodType:
  31. if ival.function.__func__ == oldFunction:
  32. # print 'found: ', ival.function, oldFunction
  33. if sys.version_info >= (3, 0):
  34. ival.function = types.MethodType(newFunction,
  35. ival.function.__self__)
  36. else:
  37. ival.function = types.MethodType(newFunction,
  38. ival.function.__self__,
  39. ival.function.__self__.__class__)
  40. count += 1
  41. return count
  42. # create FunctionInterval DirectNotify category
  43. notify = directNotify.newCategory('FunctionInterval')
  44. # Class methods
  45. def __init__(self, function, **kw):
  46. """__init__(function, name = None, openEnded = 1, extraArgs = [])
  47. """
  48. name = kw.pop('name', None)
  49. openEnded = kw.pop('openEnded', 1)
  50. extraArgs = kw.pop('extraArgs', [])
  51. # Record instance variables
  52. self.function = function
  53. # Create a unique name for the interval if necessary
  54. if name is None:
  55. name = self.makeUniqueName(function)
  56. assert isinstance(name, str)
  57. # Record any arguments
  58. self.extraArgs = extraArgs
  59. self.kw = kw
  60. # Initialize superclass
  61. # Set openEnded true if privInitialize after end time cause interval
  62. # function to be called. If false, privInitialize calls have no effect
  63. # Event, Accept, Ignore intervals default to openEnded = 0
  64. # Parent, Pos, Hpr, etc intervals default to openEnded = 1
  65. Interval.Interval.__init__(self, name, duration = 0.0, openEnded = openEnded)
  66. # For rebinding, let's remember this function interval on the class
  67. if __debug__:
  68. self.FunctionIntervals[self] = 1
  69. @staticmethod
  70. def makeUniqueName(func, suffix = ''):
  71. func_name = getattr(func, '__name__', None)
  72. if func_name is None:
  73. func_name = str(func)
  74. name = 'Func-%s-%d' % (func_name, FunctionInterval.functionIntervalNum)
  75. FunctionInterval.functionIntervalNum += 1
  76. if suffix:
  77. name = '%s-%s' % (name, str(suffix))
  78. return name
  79. def privInstant(self):
  80. # Evaluate the function
  81. self.function(*self.extraArgs, **self.kw)
  82. # Print debug information
  83. self.notify.debug(
  84. 'updateFunc() - %s: executing Function' % self.name)
  85. ### FunctionInterval subclass for throwing events ###
  86. class EventInterval(FunctionInterval):
  87. # Initialization
  88. def __init__(self, event, sentArgs=[]):
  89. """__init__(event, sentArgs)
  90. """
  91. def sendFunc(event = event, sentArgs = sentArgs):
  92. messenger.send(event, sentArgs)
  93. # Create function interval
  94. FunctionInterval.__init__(self, sendFunc, name = event)
  95. ### FunctionInterval subclass for accepting hooks ###
  96. class AcceptInterval(FunctionInterval):
  97. # Initialization
  98. def __init__(self, dirObj, event, function, name = None):
  99. """__init__(dirObj, event, function, name)
  100. """
  101. def acceptFunc(dirObj = dirObj, event = event, function = function):
  102. dirObj.accept(event, function)
  103. # Determine name
  104. if (name == None):
  105. name = 'Accept-' + event
  106. # Create function interval
  107. FunctionInterval.__init__(self, acceptFunc, name = name)
  108. ### FunctionInterval subclass for ignoring events ###
  109. class IgnoreInterval(FunctionInterval):
  110. # Initialization
  111. def __init__(self, dirObj, event, name = None):
  112. """__init__(dirObj, event, name)
  113. """
  114. def ignoreFunc(dirObj = dirObj, event = event):
  115. dirObj.ignore(event)
  116. # Determine name
  117. if (name == None):
  118. name = 'Ignore-' + event
  119. # Create function interval
  120. FunctionInterval.__init__(self, ignoreFunc, name = name)
  121. ### Function Interval subclass for adjusting scene graph hierarchy ###
  122. class ParentInterval(FunctionInterval):
  123. # ParentInterval counter
  124. parentIntervalNum = 1
  125. # Initialization
  126. def __init__(self, nodePath, parent, name = None):
  127. """__init__(nodePath, parent, name)
  128. """
  129. def reparentFunc(nodePath = nodePath, parent = parent):
  130. nodePath.reparentTo(parent)
  131. # Determine name
  132. if (name == None):
  133. name = 'ParentInterval-%d' % ParentInterval.parentIntervalNum
  134. ParentInterval.parentIntervalNum += 1
  135. # Create function interval
  136. FunctionInterval.__init__(self, reparentFunc, name = name)
  137. ### Function Interval subclass for adjusting scene graph hierarchy ###
  138. class WrtParentInterval(FunctionInterval):
  139. # WrtParentInterval counter
  140. wrtParentIntervalNum = 1
  141. # Initialization
  142. def __init__(self, nodePath, parent, name = None):
  143. """__init__(nodePath, parent, name)
  144. """
  145. def wrtReparentFunc(nodePath = nodePath, parent = parent):
  146. nodePath.wrtReparentTo(parent)
  147. # Determine name
  148. if (name == None):
  149. name = ('WrtParentInterval-%d' %
  150. WrtParentInterval.wrtParentIntervalNum)
  151. WrtParentInterval.wrtParentIntervalNum += 1
  152. # Create function interval
  153. FunctionInterval.__init__(self, wrtReparentFunc, name = name)
  154. ### Function Interval subclasses for instantaneous pose changes ###
  155. class PosInterval(FunctionInterval):
  156. # PosInterval counter
  157. posIntervalNum = 1
  158. # Initialization
  159. def __init__(self, nodePath, pos, duration = 0.0,
  160. name = None, other = None):
  161. """__init__(nodePath, pos, duration, name)
  162. """
  163. # Create function
  164. def posFunc(np = nodePath, pos = pos, other = other):
  165. if other:
  166. np.setPos(other, pos)
  167. else:
  168. np.setPos(pos)
  169. # Determine name
  170. if (name == None):
  171. name = 'PosInterval-%d' % PosInterval.posIntervalNum
  172. PosInterval.posIntervalNum += 1
  173. # Create function interval
  174. FunctionInterval.__init__(self, posFunc, name = name)
  175. class HprInterval(FunctionInterval):
  176. # HprInterval counter
  177. hprIntervalNum = 1
  178. # Initialization
  179. def __init__(self, nodePath, hpr, duration = 0.0,
  180. name = None, other = None):
  181. """__init__(nodePath, hpr, duration, name)
  182. """
  183. # Create function
  184. def hprFunc(np = nodePath, hpr = hpr, other = other):
  185. if other:
  186. np.setHpr(other, hpr)
  187. else:
  188. np.setHpr(hpr)
  189. # Determine name
  190. if (name == None):
  191. name = 'HprInterval-%d' % HprInterval.hprIntervalNum
  192. HprInterval.hprIntervalNum += 1
  193. # Create function interval
  194. FunctionInterval.__init__(self, hprFunc, name = name)
  195. class ScaleInterval(FunctionInterval):
  196. # ScaleInterval counter
  197. scaleIntervalNum = 1
  198. # Initialization
  199. def __init__(self, nodePath, scale, duration = 0.0,
  200. name = None, other = None):
  201. """__init__(nodePath, scale, duration, name)
  202. """
  203. # Create function
  204. def scaleFunc(np = nodePath, scale = scale, other = other):
  205. if other:
  206. np.setScale(other, scale)
  207. else:
  208. np.setScale(scale)
  209. # Determine name
  210. if (name == None):
  211. name = 'ScaleInterval-%d' % ScaleInterval.scaleIntervalNum
  212. ScaleInterval.scaleIntervalNum += 1
  213. # Create function interval
  214. FunctionInterval.__init__(self, scaleFunc, name = name)
  215. class PosHprInterval(FunctionInterval):
  216. # PosHprInterval counter
  217. posHprIntervalNum = 1
  218. # Initialization
  219. def __init__(self, nodePath, pos, hpr, duration = 0.0,
  220. name = None, other = None):
  221. """__init__(nodePath, pos, hpr, duration, name)
  222. """
  223. # Create function
  224. def posHprFunc(np = nodePath, pos = pos, hpr = hpr, other = other):
  225. if other:
  226. np.setPosHpr(other, pos, hpr)
  227. else:
  228. np.setPosHpr(pos, hpr)
  229. # Determine name
  230. if (name == None):
  231. name = 'PosHprInterval-%d' % PosHprInterval.posHprIntervalNum
  232. PosHprInterval.posHprIntervalNum += 1
  233. # Create function interval
  234. FunctionInterval.__init__(self, posHprFunc, name = name)
  235. class HprScaleInterval(FunctionInterval):
  236. # HprScaleInterval counter
  237. hprScaleIntervalNum = 1
  238. # Initialization
  239. def __init__(self, nodePath, hpr, scale, duration = 0.0,
  240. name = None, other = None):
  241. """__init__(nodePath, hpr, scale, duration, other, name)
  242. """
  243. # Create function
  244. def hprScaleFunc(np=nodePath, hpr=hpr, scale=scale,
  245. other = other):
  246. if other:
  247. np.setHprScale(other, hpr, scale)
  248. else:
  249. np.setHprScale(hpr, scale)
  250. # Determine name
  251. if (name == None):
  252. name = ('HprScale-%d' %
  253. HprScaleInterval.hprScaleIntervalNum)
  254. HprScaleInterval.hprScaleIntervalNum += 1
  255. # Create function interval
  256. FunctionInterval.__init__(self, hprScaleFunc, name = name)
  257. class PosHprScaleInterval(FunctionInterval):
  258. # PosHprScaleInterval counter
  259. posHprScaleIntervalNum = 1
  260. # Initialization
  261. def __init__(self, nodePath, pos, hpr, scale, duration = 0.0,
  262. name = None, other = None):
  263. """__init__(nodePath, pos, hpr, scale, duration, other, name)
  264. """
  265. # Create function
  266. def posHprScaleFunc(np=nodePath, pos=pos, hpr=hpr, scale=scale,
  267. other = other):
  268. if other:
  269. np.setPosHprScale(other, pos, hpr, scale)
  270. else:
  271. np.setPosHprScale(pos, hpr, scale)
  272. # Determine name
  273. if (name == None):
  274. name = ('PosHprScale-%d' %
  275. PosHprScaleInterval.posHprScaleIntervalNum)
  276. PosHprScaleInterval.posHprScaleIntervalNum += 1
  277. # Create function interval
  278. FunctionInterval.__init__(self, posHprScaleFunc, name = name)
  279. class Func(FunctionInterval):
  280. def __init__(self, *args, **kw):
  281. function = args[0]
  282. assert hasattr(function, '__call__')
  283. extraArgs = args[1:]
  284. kw['extraArgs'] = extraArgs
  285. FunctionInterval.__init__(self, function, **kw)
  286. class Wait(WaitInterval):
  287. def __init__(self, duration):
  288. WaitInterval.__init__(self, duration)
  289. """
  290. SAMPLE CODE
  291. from IntervalGlobal import *
  292. i1 = Func(base.transitions.fadeOut)
  293. i2 = Func(base.transitions.fadeIn)
  294. def caughtIt():
  295. print 'Caught here-is-an-event'
  296. class DummyAcceptor(DirectObject):
  297. pass
  298. da = DummyAcceptor()
  299. i3 = Func(da.accept, 'here-is-an-event', caughtIt)
  300. i4 = Func(messenger.send, 'here-is-an-event')
  301. i5 = Func(da.ignore, 'here-is-an-event')
  302. # Using a function
  303. def printDone():
  304. print 'done'
  305. i6 = Func(printDone)
  306. # Create track
  307. t1 = Sequence([
  308. # Fade out
  309. (0.0, i1),
  310. # Fade in
  311. (2.0, i2),
  312. # Accept event
  313. (4.0, i3),
  314. # Throw it,
  315. (5.0, i4),
  316. # Ignore event
  317. (6.0, i5),
  318. # Throw event again and see if ignore worked
  319. (7.0, i4),
  320. # Print done
  321. (8.0, i6)], name = 'demo')
  322. # Play track
  323. t1.play()
  324. ### Specifying interval start times during track construction ###
  325. # Interval start time can be specified relative to three different points:
  326. # PREVIOUS_END
  327. # PREVIOUS_START
  328. # TRACK_START
  329. startTime = 0.0
  330. def printStart():
  331. global startTime
  332. startTime = globalClock.getFrameTime()
  333. print 'Start'
  334. def printPreviousStart():
  335. global startTime
  336. currTime = globalClock.getFrameTime()
  337. print 'PREVIOUS_END %0.2f' % (currTime - startTime)
  338. def printPreviousEnd():
  339. global startTime
  340. currTime = globalClock.getFrameTime()
  341. print 'PREVIOUS_END %0.2f' % (currTime - startTime)
  342. def printTrackStart():
  343. global startTime
  344. currTime = globalClock.getFrameTime()
  345. print 'TRACK_START %0.2f' % (currTime - startTime)
  346. i1 = Func(printStart)
  347. # Just to take time
  348. i2 = LerpPosInterval(camera, 2.0, Point3(0, 10, 5))
  349. # This will be relative to end of camera move
  350. i3 = FunctionInterval(printPreviousEnd)
  351. # Just to take time
  352. i4 = LerpPosInterval(camera, 2.0, Point3(0, 0, 5))
  353. # This will be relative to the start of the camera move
  354. i5 = FunctionInterval(printPreviousStart)
  355. # This will be relative to track start
  356. i6 = FunctionInterval(printTrackStart)
  357. # Create the track, if you don't specify offset type in tuple it defaults to
  358. # relative to TRACK_START (first entry below)
  359. t2 = Track([(0.0, i1), # i1 start at t = 0, duration = 0.0
  360. (1.0, i2, TRACK_START), # i2 start at t = 1, duration = 2.0
  361. (2.0, i3, PREVIOUS_END), # i3 start at t = 5, duration = 0.0
  362. (1.0, i4, PREVIOUS_END), # i4 start at t = 6, duration = 2.0
  363. (3.0, i5, PREVIOUS_START), # i5 start at t = 9, duration = 0.0
  364. (10.0, i6, TRACK_START)], # i6 start at t = 10, duration = 0.0
  365. name = 'startTimeDemo')
  366. t2.play()
  367. smiley = loader.loadModel('models/misc/smiley')
  368. from direct.actor import Actor
  369. donald = Actor.Actor()
  370. donald.loadModel("phase_6/models/char/donald-wheel-1000")
  371. donald.loadAnims({"steer":"phase_6/models/char/donald-wheel-wheel"})
  372. donald.reparentTo(render)
  373. seq = Sequence(Func(donald.setPos, 0, 0, 0),
  374. donald.actorInterval('steer', duration=1.0),
  375. donald.posInterval(1, Point3(0, 0, 1)),
  376. Parallel(donald.actorInterval('steer', duration=1.0),
  377. donald.posInterval(1, Point3(0, 0, 0)),
  378. ),
  379. Wait(1.0),
  380. Func(base.toggleWireframe),
  381. Wait(1.0),
  382. Parallel(donald.actorInterval('steer', duration=1.0),
  383. donald.posInterval(1, Point3(0, 0, -1)),
  384. Sequence(donald.hprInterval(1, Vec3(180, 0, 0)),
  385. donald.hprInterval(1, Vec3(0, 0, 0)),
  386. ),
  387. ),
  388. Func(base.toggleWireframe),
  389. Func(messenger.send, 'hello'),
  390. )
  391. """