AnimPanel.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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. import Pmw, os
  8. from direct.task import Task
  9. from panda3d.core import Filename, getModelPath
  10. from tkinter.simpledialog import askfloat
  11. from tkinter.filedialog import askopenfilename
  12. FRAMES = 0
  13. SECONDS = 1
  14. class AnimPanel(AppShell):
  15. # Override class variables
  16. appname = 'Anim Panel'
  17. frameWidth = 675
  18. frameHeight = 250
  19. usecommandarea = 0
  20. usestatusarea = 0
  21. index = 0
  22. def __init__(self, aList = [], parent = None, session = None, **kw):
  23. INITOPT = Pmw.INITOPT
  24. if isinstance(aList, (list, tuple)):
  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 not animFilename or animFilename == 'None':
  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. if self.destroyCallBack is not None:
  318. self.destroyCallBack()
  319. self.destroyCallBack = None
  320. AppShell.destroy(self)
  321. class ActorControl(Pmw.MegaWidget):
  322. def __init__(self, parent = None, **kw):
  323. INITOPT = Pmw.INITOPT
  324. DEFAULT_FONT = (('MS', 'Sans', 'Serif'), 12, 'bold')
  325. DEFAULT_ANIMS = ('neutral', 'run', 'walk')
  326. animList = kw.get('animList', DEFAULT_ANIMS)
  327. if len(animList) > 0:
  328. initActive = animList[0]
  329. else:
  330. initActive = DEFAULT_ANIMS[0]
  331. optiondefs = (
  332. ('text', 'Actor', self._updateLabelText),
  333. ('animPanel', None, None),
  334. ('actor', None, None),
  335. ('animList', DEFAULT_ANIMS, None),
  336. ('active', initActive, None),
  337. ('sLabel_width', 5, None),
  338. ('sLabel_font', DEFAULT_FONT, None),
  339. )
  340. self.defineoptions(kw, optiondefs)
  341. # Initialize the superclass
  342. Pmw.MegaWidget.__init__(self, parent)
  343. # Handle to the toplevels hull
  344. interior = self.interior()
  345. interior.configure(relief = RAISED, bd = 2)
  346. # Instance variables
  347. self.fps = 24
  348. self.offset = 0.0
  349. self.maxSeconds = 1.0
  350. self.currT = 0.0
  351. self.fScaleCommand = 0
  352. self.fOneShot = 0
  353. # Create component widgets
  354. self._label = self.createcomponent(
  355. 'label', (), None,
  356. Menubutton, (interior,),
  357. font=('MSSansSerif', 14, 'bold'),
  358. relief = RAISED, bd = 1,
  359. activebackground = '#909090',
  360. text = self['text'])
  361. # Top level menu
  362. labelMenu = Menu(self._label, tearoff = 0)
  363. # Menu to select display mode
  364. self.unitsVar = IntVar()
  365. self.unitsVar.set(FRAMES)
  366. displayMenu = Menu(labelMenu, tearoff = 0)
  367. displayMenu.add_radiobutton(label = 'Frame count',
  368. value = FRAMES,
  369. variable = self.unitsVar,
  370. command = self.updateDisplay)
  371. displayMenu.add_radiobutton(label = 'Seconds',
  372. value = SECONDS,
  373. variable = self.unitsVar,
  374. command = self.updateDisplay)
  375. # Items for top level menu
  376. labelMenu.add_cascade(label = 'Display Units', menu = displayMenu)
  377. # labelMenu.add_command(label = 'Set Offset', command = self.setOffset)
  378. labelMenu.add_command(label = 'Jump To Zero',
  379. command = self.resetToZero)
  380. labelMenu.add_command(label = 'Jump To End Time',
  381. command = self.resetToEnd)
  382. # Now associate menu with menubutton
  383. self._label['menu'] = labelMenu
  384. self._label.pack(side = LEFT, fill = X)
  385. # Combo box to select current animation
  386. self.animMenu = self.createcomponent(
  387. 'animMenu', (), None,
  388. Pmw.ComboBox, (interior,),
  389. labelpos = W, label_text = 'Anim:',
  390. entry_width = 12, selectioncommand = self.selectAnimNamed,
  391. scrolledlist_items = self['animList'])
  392. self.animMenu.selectitem(self['active'])
  393. self.animMenu.pack(side = 'left', padx = 5, expand = 0)
  394. # Combo box to select frame rate
  395. playRateList = ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0', '10.0']
  396. playRate = '%0.1f' % self['actor'].getPlayRate(self['active'])
  397. if playRate not in playRateList:
  398. def strCmp(a, b):
  399. return cmp(eval(a), eval(b))
  400. playRateList.append(playRate)
  401. playRateList.sort(strCmp)
  402. playRateMenu = self.createcomponent(
  403. 'playRateMenu', (), None,
  404. Pmw.ComboBox, (interior,),
  405. labelpos = W, label_text = 'Play Rate:',
  406. entry_width = 4, selectioncommand = self.setPlayRate,
  407. scrolledlist_items = playRateList)
  408. playRateMenu.selectitem(playRate)
  409. playRateMenu.pack(side = LEFT, padx = 5, expand = 0)
  410. # Scale to control animation
  411. frameFrame = Frame(interior, relief = SUNKEN, bd = 1)
  412. self.minLabel = self.createcomponent(
  413. 'minLabel', (), 'sLabel',
  414. Label, (frameFrame,),
  415. text = 0)
  416. self.minLabel.pack(side = LEFT)
  417. self.frameControl = self.createcomponent(
  418. 'scale', (), None,
  419. Scale, (frameFrame,),
  420. from_ = 0, to = 24, resolution = 1.0,
  421. command = self.goTo,
  422. orient = HORIZONTAL, showvalue = 1)
  423. self.frameControl.pack(side = LEFT, expand = 1)
  424. self.frameControl.bind('<Button-1>', self.__onPress)
  425. self.frameControl.bind('<ButtonRelease-1>', self.__onRelease)
  426. self.maxLabel = self.createcomponent(
  427. 'maxLabel', (), 'sLabel',
  428. Label, (frameFrame,),
  429. text = 24)
  430. self.maxLabel.pack(side = LEFT)
  431. frameFrame.pack(side = LEFT, expand = 1, fill = X)
  432. # Checkbutton to enable/disable control
  433. self.frameActiveVar = IntVar()
  434. self.frameActiveVar.set(1)
  435. frameActive = self.createcomponent(
  436. 'checkbutton', (), None,
  437. Checkbutton, (interior,),
  438. variable = self.frameActiveVar)
  439. frameActive.pack(side = LEFT, expand = 1)
  440. # Execute option callbacks
  441. self.initialiseoptions(ActorControl)
  442. self.playRate = 1.0
  443. self.updateDisplay()
  444. def _updateLabelText(self):
  445. self._label['text'] = self['text']
  446. def updateDisplay(self):
  447. actor = self['actor']
  448. active = self['active']
  449. self.fps = actor.getFrameRate(active)
  450. if (self.fps == None):
  451. # there was probably a problem loading the
  452. # active animation, set default anim properties
  453. print("unable to get animation fps, zeroing out animation info")
  454. self.fps = 24
  455. self.duration = 0
  456. self.maxFrame = 0
  457. self.maxSeconds = 0
  458. else:
  459. self.duration = actor.getDuration(active)
  460. self.maxFrame = actor.getNumFrames(active) - 1
  461. self.maxSeconds = self.offset + self.duration
  462. # switch between showing frame counts and seconds
  463. if self.unitsVar.get() == FRAMES:
  464. # these are approximate due to discrete frame size
  465. fromFrame = 0
  466. toFrame = self.maxFrame
  467. self.minLabel['text'] = fromFrame
  468. self.maxLabel['text'] = toFrame
  469. self.frameControl.configure(from_ = fromFrame,
  470. to = toFrame,
  471. resolution = 1.0)
  472. else:
  473. self.minLabel['text'] = '0.0'
  474. self.maxLabel['text'] = "%.2f" % self.duration
  475. self.frameControl.configure(from_ = 0.0,
  476. to = self.duration,
  477. resolution = 0.01)
  478. def __onPress(self, event):
  479. # Enable slider command
  480. self.fScaleCommand = 1
  481. def __onRelease(self, event):
  482. # Disable slider command
  483. self.fScaleCommand = 0
  484. def selectAnimNamed(self, name):
  485. # Update active anim
  486. self['active'] = name
  487. # Reset play rate
  488. self.component('playRateMenu').selectitem('1.0')
  489. self.setPlayRate('1.0')
  490. # Move slider to zero
  491. self.resetToZero()
  492. def setPlayRate(self, rate):
  493. # set play rate on the actor, although for the AnimPanel
  494. # purpose we don't use the actor's play rate, but rather
  495. # the self.playRate value since we drive the animation
  496. # playback ourselves
  497. self['actor'].setPlayRate(eval(rate), self['active'])
  498. self.playRate = eval(rate)
  499. self.updateDisplay()
  500. def setOffset(self):
  501. newOffset = askfloat(parent = self.interior(),
  502. title = self['text'],
  503. prompt = 'Start offset (seconds):')
  504. if newOffset != None:
  505. self.offset = newOffset
  506. self.updateDisplay()
  507. def enableControl(self):
  508. self.frameActiveVar.set(1)
  509. def disableControl(self):
  510. self.frameActiveVar.set(0)
  511. def displayFrameCounts(self):
  512. self.unitsVar.set(FRAMES)
  513. self.updateDisplay()
  514. def displaySeconds(self):
  515. self.unitsVar.set(SECONDS)
  516. self.updateDisplay()
  517. def play(self, deltaT, fLoop):
  518. if self.frameActiveVar.get():
  519. # Compute new time
  520. self.currT = self.currT + deltaT
  521. if fLoop and self.duration:
  522. # If its looping compute modulo
  523. loopT = self.currT % self.duration
  524. self.goToT(loopT)
  525. else:
  526. if (self.currT > self.maxSeconds):
  527. # Clear this actor control from play list
  528. self['animPanel'].playList.remove(self)
  529. else:
  530. self.goToT(self.currT)
  531. else:
  532. # Clear this actor control from play list
  533. self['animPanel'].playList.remove(self)
  534. def goToF(self, f):
  535. if self.unitsVar.get() == FRAMES:
  536. self.frameControl.set(f)
  537. else:
  538. self.frameControl.set(f/self.fps)
  539. def goToT(self, t):
  540. if self.unitsVar.get() == FRAMES:
  541. self.frameControl.set(t * self.fps)
  542. else:
  543. self.frameControl.set(t)
  544. def goTo(self, t):
  545. # Convert scale value to float
  546. t = float(t)
  547. # Now convert t to seconds for offset calculations
  548. if self.unitsVar.get() == FRAMES:
  549. t = t / self.fps
  550. # Update currT
  551. if self.fScaleCommand or self.fOneShot:
  552. self.currT = t
  553. self.fOneShot = 0
  554. # Now update actor (pose specifed as frame count)
  555. self['actor'].pose(self['active'],
  556. min(self.maxFrame, int(t * self.fps)))
  557. def resetToZero(self):
  558. # This flag forces self.currT to be updated to new value
  559. self.fOneShot = 1
  560. self.goToT(0)
  561. def resetToEnd(self):
  562. # This flag forces self.currT to be updated to new value
  563. self.fOneShot = 1
  564. self.goToT(self.duration)
  565. def nextFrame(self):
  566. """
  567. There needed to be a better way to select an exact frame number
  568. as the control slider doesn't have the desired resolution
  569. """
  570. self.fOneShot = 1
  571. self.goToT((self.currT+(1/self.fps))%self.duration)
  572. def previousFrame(self):
  573. """
  574. There needed to be a better way to select an exact frame number
  575. as the control slider doesn't have the desired resolution
  576. """
  577. self.fOneShot = 1
  578. self.goToT((self.currT-(1/self.fps))%self.duration)
  579. """
  580. # EXAMPLE CODE
  581. from direct.actor import Actor
  582. import AnimPanel
  583. a = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
  584. "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
  585. "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
  586. 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
  587. "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
  588. "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
  589. 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
  590. "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
  591. "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
  592. {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
  593. "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
  594. "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
  595. "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
  596. "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
  597. "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
  598. a.attach("head", "torso", "joint-head", 250)
  599. a.attach("torso", "legs", "joint-hips", 250)
  600. a.attach("head", "torso", "joint-head", 500)
  601. a.attach("torso", "legs", "joint-hips", 500)
  602. a.attach("head", "torso", "joint-head", 1000)
  603. a.attach("torso", "legs", "joint-hips", 1000)
  604. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
  605. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
  606. a.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
  607. a.setLOD(250, 250, 75)
  608. a.setLOD(500, 75, 15)
  609. a.setLOD(1000, 15, 1)
  610. a.fixBounds()
  611. a.reparentTo(render)
  612. a2 = Actor.Actor({250:{"head":"phase_3/models/char/dogMM_Shorts-head-250",
  613. "torso":"phase_3/models/char/dogMM_Shorts-torso-250",
  614. "legs":"phase_3/models/char/dogMM_Shorts-legs-250"},
  615. 500:{"head":"phase_3/models/char/dogMM_Shorts-head-500",
  616. "torso":"phase_3/models/char/dogMM_Shorts-torso-500",
  617. "legs":"phase_3/models/char/dogMM_Shorts-legs-500"},
  618. 1000:{"head":"phase_3/models/char/dogMM_Shorts-head-1000",
  619. "torso":"phase_3/models/char/dogMM_Shorts-torso-1000",
  620. "legs":"phase_3/models/char/dogMM_Shorts-legs-1000"}},
  621. {"head":{"walk":"phase_3/models/char/dogMM_Shorts-head-walk", \
  622. "run":"phase_3/models/char/dogMM_Shorts-head-run"}, \
  623. "torso":{"walk":"phase_3/models/char/dogMM_Shorts-torso-walk", \
  624. "run":"phase_3/models/char/dogMM_Shorts-torso-run"}, \
  625. "legs":{"walk":"phase_3/models/char/dogMM_Shorts-legs-walk", \
  626. "run":"phase_3/models/char/dogMM_Shorts-legs-run"}})
  627. a2.attach("head", "torso", "joint-head", 250)
  628. a2.attach("torso", "legs", "joint-hips", 250)
  629. a2.attach("head", "torso", "joint-head", 500)
  630. a2.attach("torso", "legs", "joint-hips", 500)
  631. a2.attach("head", "torso", "joint-head", 1000)
  632. a2.attach("torso", "legs", "joint-hips", 1000)
  633. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=250)
  634. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=500)
  635. a2.drawInFront("joint-pupil?", "eyes*", -1, lodName=1000)
  636. a2.setLOD(250, 250, 75)
  637. a2.setLOD(500, 75, 15)
  638. a2.setLOD(1000, 15, 1)
  639. a2.fixBounds()
  640. a2.reparentTo(render)
  641. ap = AnimPanel.AnimPanel([a, a2])
  642. # Alternately
  643. ap = a.animPanel()
  644. ap2 = a2.animPanel()
  645. """