AnimPanel.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. """DIRECT Animation Control Panel"""
  2. __all__ = ['AnimPanel', 'ActorControl']
  3. ### SEE END OF FILE FOR EXAMPLE USEAGE ###
  4. # Import Tkinter, Pmw, and the floater code from this directory tree.
  5. from direct.tkwidgets.AppShell import *
  6. from direct.showbase.TkGlobal import *
  7. from tkSimpleDialog import askfloat
  8. from Tkinter import *
  9. import Pmw, string, math, types
  10. from direct.task import Task
  11. FRAMES = 0
  12. SECONDS = 1
  13. class AnimPanel(AppShell):
  14. # Override class variables
  15. appname = 'Anim Panel'
  16. frameWidth = 675
  17. frameHeight = 250
  18. usecommandarea = 0
  19. usestatusarea = 0
  20. index = 0
  21. def __init__(self, aList = [], parent = None, session = None, **kw):
  22. INITOPT = Pmw.INITOPT
  23. if ((type(aList) == types.ListType) or
  24. (type(aList) == types.TupleType)):
  25. kw['actorList'] = aList
  26. else:
  27. kw['actorList'] = [aList]
  28. optiondefs = (
  29. ('title', self.appname, None),
  30. ('actorList', [], None),
  31. ('Actor_label_width', 12, None),
  32. )
  33. self.defineoptions(kw, optiondefs)
  34. # direct session that spawned me, if any, used
  35. # for certain interactions with the session such
  36. # as being able to see selected objects/actors
  37. self.session = session
  38. self.frameHeight = 60 + (50 * len(self['actorList']))
  39. self.playList = []
  40. self.id = 'AnimPanel_%d' % AnimPanel.index
  41. AnimPanel.index += 1
  42. # current index used for creating new actor controls
  43. self.actorControlIndex = 0
  44. # Initialize the superclass
  45. AppShell.__init__(self)
  46. # Execute option callbacks
  47. self.initialiseoptions(AnimPanel)
  48. # We need to know when AnimPanel is closed
  49. self.destroyCallBack = None
  50. def createInterface(self):
  51. # Handle to the toplevels interior
  52. interior = self.interior()
  53. menuBar = self.menuBar
  54. menuBar.addmenu('AnimPanel', 'Anim Panel Operations')
  55. # Actor control status
  56. menuBar.addcascademenu('AnimPanel', 'Control Status',
  57. 'Enable/disable actor control panels')
  58. menuBar.addmenuitem('Control Status', 'command',
  59. 'Enable all actor controls',
  60. label = 'Enable all',
  61. command = self.enableActorControls)
  62. menuBar.addmenuitem('Control Status', 'command',
  63. 'Disable all actor controls',
  64. label = 'Disable all',
  65. command = self.disableActorControls)
  66. # Frame Slider units
  67. menuBar.addcascademenu('AnimPanel', 'Display Units',
  68. 'Select display units')
  69. menuBar.addmenuitem('Display Units', 'command',
  70. 'Display frame counts', label = 'Frame count',
  71. command = self.displayFrameCounts)
  72. menuBar.addmenuitem('Display Units', 'command',
  73. 'Display seconds', label = 'Seconds',
  74. command = self.displaySeconds)
  75. # Reset all actor controls
  76. menuBar.addmenuitem('AnimPanel', 'command',
  77. 'Set actor controls to t = 0.0',
  78. label = 'Jump all to zero',
  79. command = self.resetAllToZero)
  80. menuBar.addmenuitem('AnimPanel', 'command',
  81. 'Set Actor controls to end time',
  82. label = 'Jump all to end time',
  83. command = self.resetAllToEnd)
  84. # Add some buttons to update all Actor Controls
  85. self.fToggleAll = 1
  86. b = self.createcomponent(
  87. 'toggleEnableButton', (), None,
  88. Button, (self.menuFrame,),
  89. text = 'Toggle Enable',
  90. command = self.toggleAllControls)
  91. b.pack(side = RIGHT, expand = 0)
  92. b = self.createcomponent(
  93. 'showSecondsButton', (), None,
  94. Button, (self.menuFrame,),
  95. text = 'Show Seconds',
  96. command = self.displaySeconds)
  97. b.pack(side = RIGHT, expand = 0)
  98. b = self.createcomponent(
  99. 'showFramesButton', (), None,
  100. Button, (self.menuFrame,),
  101. text = 'Show Frames',
  102. command = self.displayFrameCounts)
  103. b.pack(side = RIGHT, expand = 0)
  104. self.actorFrame = None
  105. self.createActorControls()
  106. # Create a frame to hold the playback controls
  107. controlFrame = Frame(interior)
  108. self.toStartButton = self.createcomponent(
  109. 'toStart', (), None,
  110. Button, (controlFrame,),
  111. text = '<<',
  112. width = 4,
  113. command = self.resetAllToZero)
  114. self.toStartButton.pack(side = LEFT, expand = 1, fill = X)
  115. self.toPreviousFrameButton = self.createcomponent(
  116. 'toPreviousFrame', (), None,
  117. Button, (controlFrame,),
  118. text = '<',
  119. width = 4,
  120. command = self.previousFrame)
  121. self.toPreviousFrameButton.pack(side = LEFT, expand = 1, fill = X)
  122. self.playButton = self.createcomponent(
  123. 'playButton', (), None,
  124. Button, (controlFrame,),
  125. text = 'Play', width = 8,
  126. command = self.playActorControls)
  127. self.playButton.pack(side = LEFT, expand = 1, fill = X)
  128. self.stopButton = self.createcomponent(
  129. 'stopButton', (), None,
  130. Button, (controlFrame,),
  131. text = 'Stop', width = 8,
  132. command = self.stopActorControls)
  133. self.stopButton.pack(side = LEFT, expand = 1, fill = X)
  134. self.toNextFrameButton = self.createcomponent(
  135. 'toNextFrame', (), None,
  136. Button, (controlFrame,),
  137. text = '>',
  138. width = 4,
  139. command = self.nextFrame)
  140. self.toNextFrameButton.pack(side = LEFT, expand = 1, fill = X)
  141. self.toEndButton = self.createcomponent(
  142. 'toEnd', (), None,
  143. Button, (controlFrame,),
  144. text = '>>',
  145. width = 4,
  146. command = self.resetAllToEnd)
  147. self.toEndButton.pack(side = LEFT, expand = 1, fill = X)
  148. self.loopVar = IntVar()
  149. self.loopVar.set(0)
  150. self.loopButton = self.createcomponent(
  151. 'loopButton', (), None,
  152. Checkbutton, (controlFrame,),
  153. text = 'Loop', width = 8,
  154. variable = self.loopVar)
  155. self.loopButton.pack(side = LEFT, expand = 1, fill = X)
  156. # add actors and animations, only allowed if a direct
  157. # session has been specified since these currently require
  158. # interaction with selected objects
  159. if (self.session):
  160. menuBar.addmenuitem('File', 'command',
  161. 'Set currently selected group of objects as actors to animate.',
  162. label = 'Set Actors',
  163. command = self.setActors)
  164. menuBar.addmenuitem('File', 'command',
  165. 'Load animation file',
  166. label = 'Load Anim',
  167. command = self.loadAnim)
  168. controlFrame.pack(fill = X)
  169. def createActorControls(self):
  170. # Create a frame to hold all the actor controls
  171. self.actorFrame = Frame(self.interior())
  172. # Create a control for each actor
  173. self.actorControlList = []
  174. for actor in self['actorList']:
  175. anims = actor.getAnimNames()
  176. print "actor animnames: %s"%anims
  177. topAnims = []
  178. if 'neutral' in anims:
  179. i = anims.index('neutral')
  180. del(anims[i])
  181. topAnims.append('neutral')
  182. if 'walk' in anims:
  183. i = anims.index('walk')
  184. del(anims[i])
  185. topAnims.append('walk')
  186. if 'run' in anims:
  187. i = anims.index('run')
  188. del(anims[i])
  189. topAnims.append('run')
  190. anims.sort()
  191. anims = topAnims + anims
  192. if (len(anims)== 0):
  193. # no animations set for this actor, don't
  194. # display the control panel
  195. continue
  196. # currComponents = self.components()
  197. # if ('actorControl%d' % index in currComponents):
  198. # self.destroycomponent('actorControl%d' % index)
  199. # ac = self.component('actorControl%d' % index)
  200. # if (ac == None):
  201. ac = self.createcomponent(
  202. 'actorControl%d' % self.actorControlIndex, (), 'Actor',
  203. ActorControl, (self.actorFrame,),
  204. animPanel = self,
  205. text = actor.getName(),
  206. animList = anims,
  207. actor = actor)
  208. ac.pack(expand = 1, fill = X)
  209. self.actorControlList.append(ac)
  210. self.actorControlIndex = self.actorControlIndex + 1
  211. # Now pack the actor frame
  212. self.actorFrame.pack(expand = 1, fill = BOTH)
  213. def clearActorControls(self):
  214. if (self.actorFrame):
  215. self.actorFrame.forget()
  216. self.actorFrame.destroy()
  217. self.actorFrame = None
  218. def setActors(self):
  219. self.stopActorControls()
  220. actors = self.session.getSelectedActors()
  221. # make sure selected objects are actors, if not don't
  222. # use?
  223. aList = []
  224. for currActor in actors:
  225. aList.append(currActor)
  226. self['actorList'] = aList
  227. self.clearActorControls()
  228. self.createActorControls()
  229. def loadAnim(self):
  230. # bring up file open box to allow selection of an
  231. # animation file
  232. animFilename = askopenfilename(
  233. defaultextension = '.mb',
  234. filetypes = (('Maya Models', '*.mb'),
  235. ('All files', '*')),
  236. initialdir = '/i/beta',
  237. title = 'Load Animation',
  238. parent = self.component('hull')
  239. )
  240. if (animFilename == ''):
  241. # no file selected, canceled
  242. return
  243. # add directory where animation was loaded from to the
  244. # current model path so any further searches for the file
  245. # can find it
  246. fileDirName = os.path.dirname(animFilename)
  247. fileBaseName = os.path.basename(animFilename)
  248. fileBaseNameBase = os.path.splitext(fileBaseName)[0]
  249. fileDirNameFN = Filename(fileDirName)
  250. fileDirNameFN.makeCanonical()
  251. getModelPath().prependDirectory(fileDirNameFN)
  252. for currActor in self['actorList']:
  253. # replace all currently loaded anims with specified one
  254. # currActor.unloadAnims(None, None, None)
  255. currActor.loadAnims({fileBaseNameBase:fileBaseNameBase})
  256. self.clearActorControls()
  257. self.createActorControls()
  258. def playActorControls(self):
  259. self.stopActorControls()
  260. self.lastT = globalClock.getFrameTime()
  261. self.playList = self.actorControlList[:]
  262. taskMgr.add(self.play, self.id + '_UpdateTask')
  263. def play(self, task):
  264. if not self.playList:
  265. return Task.done
  266. fLoop = self.loopVar.get()
  267. currT = globalClock.getFrameTime()
  268. deltaT = currT - self.lastT
  269. self.lastT = currT
  270. for actorControl in self.playList:
  271. # scale time by play rate value
  272. actorControl.play(deltaT * actorControl.playRate, fLoop)
  273. return Task.cont
  274. def stopActorControls(self):
  275. taskMgr.remove(self.id + '_UpdateTask')
  276. def getActorControlAt(self, index):
  277. return self.actorControlList[index]
  278. def enableActorControlAt(self, index):
  279. self.getActorControlAt(index).enableControl()
  280. def toggleAllControls(self):
  281. if self.fToggleAll:
  282. self.disableActorControls()
  283. else:
  284. self.enableActorControls()
  285. self.fToggleAll = 1 - self.fToggleAll
  286. def enableActorControls(self):
  287. for actorControl in self.actorControlList:
  288. actorControl.enableControl()
  289. def disableActorControls(self):
  290. for actorControl in self.actorControlList:
  291. actorControl.disableControl()
  292. def disableActorControlAt(self, index):
  293. self.getActorControlAt(index).disableControl()
  294. def displayFrameCounts(self):
  295. for actorControl in self.actorControlList:
  296. actorControl.displayFrameCounts()
  297. def displaySeconds(self):
  298. for actorControl in self.actorControlList:
  299. actorControl.displaySeconds()
  300. def resetAllToZero(self):
  301. for actorControl in self.actorControlList:
  302. actorControl.resetToZero()
  303. def resetAllToEnd(self):
  304. for actorControl in self.actorControlList:
  305. actorControl.resetToEnd()
  306. def nextFrame(self):
  307. for actorControl in self.actorControlList:
  308. actorControl.nextFrame()
  309. def previousFrame(self):
  310. for actorControl in self.actorControlList:
  311. actorControl.previousFrame()
  312. def setDestroyCallBack(self, callBack):
  313. self.destroyCallBack = callBack
  314. def destroy(self):
  315. # First clean up
  316. taskMgr.remove(self.id + '_UpdateTask')
  317. self.destroyCallBack()
  318. self.destroyCallBack = None
  319. AppShell.destroy(self)
  320. class ActorControl(Pmw.MegaWidget):
  321. def __init__(self, parent = None, **kw):
  322. INITOPT = Pmw.INITOPT
  323. DEFAULT_FONT = (('MS', 'Sans', 'Serif'), 12, 'bold')
  324. DEFAULT_ANIMS = ('neutral', 'run', 'walk')
  325. animList = kw.get('animList', DEFAULT_ANIMS)
  326. if len(animList) > 0:
  327. initActive = animList[0]
  328. else:
  329. initActive = DEFAULT_ANIMS[0]
  330. optiondefs = (
  331. ('text', 'Actor', self._updateLabelText),
  332. ('animPanel', None, None),
  333. ('actor', None, None),
  334. ('animList', DEFAULT_ANIMS, None),
  335. ('active', initActive, None),
  336. ('sLabel_width', 5, None),
  337. ('sLabel_font', DEFAULT_FONT, None),
  338. )
  339. self.defineoptions(kw, optiondefs)
  340. # Initialize the superclass
  341. Pmw.MegaWidget.__init__(self, parent)
  342. # Handle to the toplevels hull
  343. interior = self.interior()
  344. interior.configure(relief = RAISED, bd = 2)
  345. # Instance variables
  346. self.fps = 24
  347. self.offset = 0.0
  348. self.maxSeconds = 1.0
  349. self.currT = 0.0
  350. self.fScaleCommand = 0
  351. self.fOneShot = 0
  352. # Create component widgets
  353. self._label = self.createcomponent(
  354. 'label', (), None,
  355. Menubutton, (interior,),
  356. font=('MSSansSerif', 14, 'bold'),
  357. relief = RAISED, bd = 1,
  358. activebackground = '#909090',
  359. text = self['text'])
  360. # Top level menu
  361. labelMenu = Menu(self._label, tearoff = 0)
  362. # Menu to select display mode
  363. self.unitsVar = IntVar()
  364. self.unitsVar.set(FRAMES)
  365. displayMenu = Menu(labelMenu, tearoff = 0)
  366. displayMenu.add_radiobutton(label = 'Frame count',
  367. value = FRAMES,
  368. variable = self.unitsVar,
  369. command = self.updateDisplay)
  370. displayMenu.add_radiobutton(label = 'Seconds',
  371. value = SECONDS,
  372. variable = self.unitsVar,
  373. command = self.updateDisplay)
  374. # Items for top level menu
  375. labelMenu.add_cascade(label = 'Display Units', menu = displayMenu)
  376. # labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
  377. labelMenu.add_command(label = 'Jump To Zero',
  378. command = self.resetToZero)
  379. labelMenu.add_command(label = 'Jump To End Time',
  380. command = self.resetToEnd)
  381. # Now associate menu with menubutton
  382. self._label['menu'] = labelMenu
  383. self._label.pack(side = LEFT, fill = X)
  384. # Combo box to select current animation
  385. self.animMenu = self.createcomponent(
  386. 'animMenu', (), None,
  387. Pmw.ComboBox, (interior,),
  388. labelpos = W, label_text = 'Anim:',
  389. entry_width = 12, selectioncommand = self.selectAnimNamed,
  390. scrolledlist_items = self['animList'])
  391. self.animMenu.selectitem(self['active'])
  392. self.animMenu.pack(side = 'left', padx = 5, expand = 0)
  393. # Combo box to select frame rate
  394. playRateList = ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0', '10.0']
  395. playRate = '%0.1f' % self['actor'].getPlayRate(self['active'])
  396. if playRate not in playRateList:
  397. def strCmp(a, b):
  398. return cmp(eval(a), eval(b))
  399. playRateList.append(playRate)
  400. playRateList.sort(strCmp)
  401. playRateMenu = self.createcomponent(
  402. 'playRateMenu', (), None,
  403. Pmw.ComboBox, (interior,),
  404. labelpos = W, label_text = 'Play Rate:',
  405. entry_width = 4, selectioncommand = self.setPlayRate,
  406. scrolledlist_items = playRateList)
  407. playRateMenu.selectitem(playRate)
  408. playRateMenu.pack(side = LEFT, padx = 5, expand = 0)
  409. # Scale to control animation
  410. frameFrame = Frame(interior, relief = SUNKEN, bd = 1)
  411. self.minLabel = self.createcomponent(
  412. 'minLabel', (), 'sLabel',
  413. Label, (frameFrame,),
  414. text = 0)
  415. self.minLabel.pack(side = LEFT)
  416. self.frameControl = self.createcomponent(
  417. 'scale', (), None,
  418. Scale, (frameFrame,),
  419. from_ = 0, to = 24, resolution = 1.0,
  420. command = self.goTo,
  421. orient = HORIZONTAL, showvalue = 1)
  422. self.frameControl.pack(side = LEFT, expand = 1)
  423. self.frameControl.bind('<Button-1>', self.__onPress)
  424. self.frameControl.bind('<ButtonRelease-1>', self.__onRelease)
  425. self.maxLabel = self.createcomponent(
  426. 'maxLabel', (), 'sLabel',
  427. Label, (frameFrame,),
  428. text = 24)
  429. self.maxLabel.pack(side = LEFT)
  430. frameFrame.pack(side = LEFT, expand = 1, fill = X)
  431. # Checkbutton to enable/disable control
  432. self.frameActiveVar = IntVar()
  433. self.frameActiveVar.set(1)
  434. frameActive = self.createcomponent(
  435. 'checkbutton', (), None,
  436. Checkbutton, (interior,),
  437. variable = self.frameActiveVar)
  438. frameActive.pack(side = LEFT, expand = 1)
  439. # Execute option callbacks
  440. self.initialiseoptions(ActorControl)
  441. self.playRate = 1.0
  442. self.updateDisplay()
  443. def _updateLabelText(self):
  444. self._label['text'] = self['text']
  445. def updateDisplay(self):
  446. actor = self['actor']
  447. active = self['active']
  448. self.fps = actor.getFrameRate(active)
  449. if (self.fps == None):
  450. # there was probably a problem loading the
  451. # active animation, set default anim properties
  452. print "unable to get animation fps, zeroing out animation info"
  453. self.fps = 24
  454. self.duration = 0
  455. self.maxFrame = 0
  456. self.maxSeconds = 0
  457. else:
  458. self.duration = actor.getDuration(active)
  459. self.maxFrame = actor.getNumFrames(active) - 1
  460. self.maxSeconds = self.offset + self.duration
  461. # switch between showing frame counts and seconds
  462. if self.unitsVar.get() == FRAMES:
  463. # these are approximate due to discrete frame size
  464. fromFrame = 0
  465. toFrame = self.maxFrame
  466. self.minLabel['text'] = fromFrame
  467. self.maxLabel['text'] = toFrame
  468. self.frameControl.configure(from_ = fromFrame,
  469. to = toFrame,
  470. resolution = 1.0)
  471. else:
  472. self.minLabel['text'] = '0.0'
  473. self.maxLabel['text'] = "%.2f" % self.duration
  474. self.frameControl.configure(from_ = 0.0,
  475. to = self.duration,
  476. resolution = 0.01)
  477. def __onPress(self, event):
  478. # Enable slider command
  479. self.fScaleCommand = 1
  480. def __onRelease(self, event):
  481. # Disable slider command
  482. self.fScaleCommand = 0
  483. def selectAnimNamed(self, name):
  484. # Update active anim
  485. self['active'] = name
  486. # Reset play rate
  487. self.component('playRateMenu').selectitem('1.0')
  488. self.setPlayRate('1.0')
  489. # Move slider to zero
  490. self.resetToZero()
  491. def setPlayRate(self, rate):
  492. # set play rate on the actor, although for the AnimPanel
  493. # purpose we don't use the actor's play rate, but rather
  494. # the self.playRate value since we drive the animation
  495. # playback ourselves
  496. self['actor'].setPlayRate(eval(rate), self['active'])
  497. self.playRate = eval(rate)
  498. self.updateDisplay()
  499. def setOffset(self):
  500. newOffset = askfloat(parent = self.interior(),
  501. title = self['text'],
  502. prompt = 'Start offset (seconds):')
  503. if newOffset != None:
  504. self.offset = newOffset
  505. self.updateDisplay()
  506. def enableControl(self):
  507. self.frameActiveVar.set(1)
  508. def disableControl(self):
  509. self.frameActiveVar.set(0)
  510. def displayFrameCounts(self):
  511. self.unitsVar.set(FRAMES)
  512. self.updateDisplay()
  513. def displaySeconds(self):
  514. self.unitsVar.set(SECONDS)
  515. self.updateDisplay()
  516. def play(self, deltaT, fLoop):
  517. if self.frameActiveVar.get():
  518. # Compute new time
  519. self.currT = self.currT + deltaT
  520. if fLoop and self.duration:
  521. # If its looping compute modulo
  522. loopT = self.currT % self.duration
  523. self.goToT(loopT)
  524. else:
  525. if (self.currT > self.maxSeconds):
  526. # Clear this actor control from play list
  527. self['animPanel'].playList.remove(self)
  528. else:
  529. self.goToT(self.currT)
  530. else:
  531. # Clear this actor control from play list
  532. self['animPanel'].playList.remove(self)
  533. def goToF(self, f):
  534. if self.unitsVar.get() == FRAMES:
  535. self.frameControl.set(f)
  536. else:
  537. self.frameControl.set(f/self.fps)
  538. def goToT(self, t):
  539. if self.unitsVar.get() == FRAMES:
  540. self.frameControl.set(t * self.fps)
  541. else:
  542. self.frameControl.set(t)
  543. def goTo(self, t):
  544. # Convert scale value to float
  545. t = string.atof(t)
  546. # Now convert t to seconds for offset calculations
  547. if self.unitsVar.get() == FRAMES:
  548. t = t / self.fps
  549. # Update currT
  550. if self.fScaleCommand or self.fOneShot:
  551. self.currT = t
  552. self.fOneShot = 0
  553. # Now update actor (pose specifed as frame count)
  554. self['actor'].pose(self['active'],
  555. min(self.maxFrame, int(t * self.fps)))
  556. def resetToZero(self):
  557. # This flag forces self.currT to be updated to new value
  558. self.fOneShot = 1
  559. self.goToT(0)
  560. def resetToEnd(self):
  561. # This flag forces self.currT to be updated to new value
  562. self.fOneShot = 1
  563. self.goToT(self.duration)
  564. def nextFrame(self):
  565. """
  566. There needed to be a better way to select an exact frame number
  567. as the control slider doesn't have the desired resolution
  568. """
  569. self.fOneShot = 1
  570. self.goToT((self.currT+(1/self.fps))%self.duration)
  571. def previousFrame(self):
  572. """
  573. There needed to be a better way to select an exact frame number
  574. as the control slider doesn't have the desired resolution
  575. """
  576. self.fOneShot = 1
  577. self.goToT((self.currT-(1/self.fps))%self.duration)
  578. """
  579. # EXAMPLE CODE
  580. from direct.actor import Actor
  581. import AnimPanel
  582. a = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
  583. "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
  584. "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
  585. 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
  586. "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
  587. "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
  588. 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
  589. "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
  590. "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
  591. {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
  592. "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
  593. "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
  594. "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
  595. "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
  596. "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
  597. a.attach("head", "torso", "joint-head", 250)
  598. a.attach("torso", "legs", "joint-hips", 250)
  599. a.attach("head", "torso", "joint-head", 500)
  600. a.attach("torso", "legs", "joint-hips", 500)
  601. a.attach("head", "torso", "joint-head", 1000)
  602. a.attach("torso", "legs", "joint-hips", 1000)
  603. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
  604. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
  605. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
  606. a.setLOD(250, 250, 75)
  607. a.setLOD(500, 75, 15)
  608. a.setLOD(1000, 15, 1)
  609. a.fixBounds()
  610. a.reparentTo(render)
  611. a2 = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
  612. "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
  613. "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
  614. 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
  615. "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
  616. "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
  617. 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
  618. "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
  619. "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
  620. {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
  621. "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
  622. "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
  623. "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
  624. "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
  625. "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
  626. a2.attach("head", "torso", "joint-head", 250)
  627. a2.attach("torso", "legs", "joint-hips", 250)
  628. a2.attach("head", "torso", "joint-head", 500)
  629. a2.attach("torso", "legs", "joint-hips", 500)
  630. a2.attach("head", "torso", "joint-head", 1000)
  631. a2.attach("torso", "legs", "joint-hips", 1000)
  632. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
  633. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
  634. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
  635. a2.setLOD(250, 250, 75)
  636. a2.setLOD(500, 75, 15)
  637. a2.setLOD(1000, 15, 1)
  638. a2.fixBounds()
  639. a2.reparentTo(render)
  640. ap = AnimPanel.AnimPanel([a, a2])
  641. # Alternately
  642. ap = a.animPanel()
  643. ap2 = a2.animPanel()
  644. """