annotate.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env python
  2. __author__ = 'Andrew Dunai <[email protected]>'
  3. import sys
  4. import json
  5. import argparse
  6. import re
  7. from collections import namedtuple
  8. try:
  9. from PyQt4 import QtGui
  10. import argparseui
  11. except ImportError:
  12. CAN_GUI = False
  13. else:
  14. CAN_GUI = True
  15. range_regexp = re.compile(r'^([\w\d]+)\=([\d]+)\.\.([\d]+)$')
  16. Range = namedtuple('Range', ('name', 'start', 'end'))
  17. def parse_range(value):
  18. match = range_regexp.match(value)
  19. if not match:
  20. raise argparse.ArgumentTypeError('Ranges should be in form "name=frame..frame"')
  21. return Range(match.group(1), int(match.group(2)) - 1, int(match.group(3)) - 1)
  22. epilog = 'example:\n %(prog)s -i model.js -o model.new.js idle=1..10 walk=11..20'
  23. if not CAN_GUI:
  24. epilog += '\npro tip:\n Install PyQt4 and argparseui packages to use GUI ("-u" option).'
  25. epilog += '\nCreated by {}'.format(__author__)
  26. parser = argparse.ArgumentParser(
  27. description='Split THREE.js model animation into seperate parts.',
  28. epilog=epilog,
  29. formatter_class=argparse.RawDescriptionHelpFormatter
  30. )
  31. CAN_GUI and parser.add_argument('-u', '--gui', help='run in GUI', dest='gui', action='store_true')
  32. parser.add_argument('-i', metavar='FILE', help='input file name', required=True, dest='source', type=argparse.FileType('r'))
  33. parser.add_argument('-o', metavar='FILE', help='output file name', required=True, dest='destination', type=argparse.FileType('w'))
  34. parser.add_argument('range', nargs='+', help='range in format "name=frame..frame"', type=parse_range)
  35. def process(parser):
  36. args = parser.parse_args()
  37. data = json.loads(args.source.read())
  38. animation = data.get('animation')
  39. fps = float(animation.get('fps'))
  40. length = float(animation.get('length'))
  41. frame_count = int(length * fps)
  42. frame_duration = 1.0 / fps
  43. all_hierarchy = animation.get('hierarchy')
  44. animations = {}
  45. for r in args.range:
  46. # Create animation & hierarchy
  47. hierarchy = []
  48. animation = {
  49. 'name': r.name,
  50. 'fps': fps,
  51. 'length': (r.end - r.start) * frame_duration,
  52. 'hierarchy': hierarchy
  53. }
  54. # Go through each bone animation
  55. for bone in all_hierarchy:
  56. keys = [key for key in bone['keys'] if (key['time'] >= r.start * frame_duration) and (key['time'] <= r.end * frame_duration)]
  57. # Patch time
  58. time = 0.0
  59. for key in keys:
  60. key['time'] = round(time, 3)
  61. time += frame_duration
  62. new_bone = {
  63. 'parent': bone['parent'],
  64. 'keys': keys
  65. }
  66. hierarchy.append(new_bone)
  67. animations[r.name] = animation
  68. del data['animation']
  69. data['animations'] = animations
  70. args.destination.write(json.dumps(data))
  71. if '-u' in sys.argv and CAN_GUI:
  72. app = QtGui.QApplication(sys.argv)
  73. a = argparseui.ArgparseUi(parser)
  74. a.show()
  75. app.exec_()
  76. if a.result() == 1:
  77. process(a)
  78. else:
  79. process(parser)