csv_anim_bck_import.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. '''
  2. CSV importer for the BCK animation type
  3. CSVs that come from the j3d animation editor program
  4. animations for now will be imported with linear interpolation
  5. seems to me that the majority of the animations just use linear
  6. as the interpolation method between keyframes of animation rows
  7. '''
  8. # Notes (AFAIK):
  9. #
  10. # - reference link --> https://wiki.cloudmodding.com/tww/BCK
  11. # - In all the Mario CSV BCKs I've seen from J3D Animation
  12. # Editor the "smooth" interpolation type isn't used at all
  13. # for animation rows that contain more than the first frame value
  14. # it could be that JAE just converts the animation to linear
  15. # timing for easier processing but I am not certain
  16. import bpy, math, re
  17. from mathutils import Matrix
  18. from .my_functions import *
  19. #################################################
  20. # read_csv_bck function (MAIN FUNCTION)
  21. # read CSV file of BCK from J3D Animation Editor
  22. # used to apply BCK animation to model on Blender
  23. #################################################
  24. def read_csv_bck(context, filepath, import_type):
  25. #
  26. # this thing is always needed for stuff
  27. scene = bpy.context.scene
  28. # if nothing is selected end the exporter
  29. if (scene.objects.active == None
  30. or
  31. scene.objects.active.type != 'ARMATURE'):
  32. error_string = "No Armature object selected. Select one and try again."
  33. print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n")
  34. show_message(error_string, "Error exporting collada file", 'ERROR')
  35. return {'FINISHED'}
  36. # get armature object
  37. armature = scene.objects.active
  38. print()
  39. print("###############")
  40. print("Armature found: %s" % armature.name)
  41. print()
  42. # deselect everything (to be sure nothing weird happens)
  43. bpy.ops.object.select_all(action='DESELECT')
  44. scene.objects.active = None
  45. # re-select the armature object only
  46. armature.select = True
  47. scene.objects.active = armature
  48. # open file to read
  49. f = open(filepath, 'r', encoding='utf-8')
  50. # check the file if it is from a BCK file and check the
  51. # number of bones, if the file is not from a BCK
  52. # or the bone count differs from the armature
  53. # bone count end the importer
  54. # first line has the animation type
  55. line = f.readline()
  56. if not (line.find("bck") + 1):
  57. error_string = "CSV is not for the BCK animation type. Check the file and try again."
  58. print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n")
  59. show_message(error_string, "Error importing CSV file data", 'ERROR')
  60. return {'FINISHED'}
  61. # count the bones of the animation on the CSV
  62. # store each time the "Scale X" is found in a line
  63. bone_count = 0
  64. while True:
  65. line = f.readline()
  66. # count the bones
  67. if (line.find("Scale X") + 1):
  68. bone_count = bone_count + 1
  69. # if an empty line or a line with a newline character
  70. # is reached end of file must've been reached
  71. if (line == "" or line == '\n'):
  72. break
  73. # check bone count
  74. if (bone_count != len(armature.data.bones)):
  75. error_string = "Number of bones on the Armature is different than the number of animated bones on the CSV. Check the CSV file and try again."
  76. print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n")
  77. show_message(error_string, "Error importing CSV file data", 'ERROR')
  78. return {'FINISHED'}
  79. ###############
  80. # file is valid
  81. ###############
  82. # start extracting animation data
  83. ###########################################################################
  84. ###########################################################################
  85. # import type "ignore rest pose"
  86. # in here I don't need to do any calculation of the data read from the CSV
  87. # the armature in which this animation is to be applied must've been
  88. # imported before in the "ignore rest pose" mode (i.e. the child bones are
  89. # in the origin of the reference system defined by the parent's bone head).
  90. # This is like this because BCK CSVs contain the data of how a child bone
  91. # moves with respect to its parent.
  92. ###########################################################################
  93. ###########################################################################
  94. if (import_type == True):
  95. #
  96. # read the CSV from the start again
  97. # to import the animation values
  98. f = open(filepath, 'r', encoding='utf-8')
  99. line = f.readline()
  100. # first line of the CSV
  101. csv_first_line = line.split(',')
  102. animation_length = int(csv_first_line[1])
  103. # get the animation last frame and set it in blender
  104. bpy.data.scenes["Scene"].frame_end = int(csv_first_line[1])
  105. # the next line comes with the notable keyframes used in the animation
  106. line = f.readline()
  107. # get all keyframe numbers
  108. csv_keyframe_numbers = re.findall('[0-9]+', line)
  109. csv_keyframe_numbers = [int(string) for string in csv_keyframe_numbers]
  110. ###############################################################
  111. # in the next loop starts the bone animation data table reading
  112. # loop through every bone
  113. ###############################################################
  114. for bone_number in range(bone_count):
  115. # get pose bone
  116. pose_bone = armature.pose.bones[bone_number]
  117. print("Reading/Writing animation for bone: %s" % (pose_bone.name))
  118. # set bone rotation mode to Extrinsic Euler XYZ
  119. pose_bone.rotation_mode = 'XYZ'
  120. # bone_anim_data will hold the bone keyframe animation
  121. # data for a single bone from the CSV file as follows
  122. # row 1 --> X scaling
  123. # row 2 --> Y scaling
  124. # row 3 --> Z scaling
  125. # row 4 --> X rotation
  126. # row 5 --> Y rotation
  127. # row 6 --> Z rotation
  128. # row 7 --> X translation
  129. # row 8 --> Y translation
  130. # row 9 --> Z translation
  131. # already initialized with 9 rows as I don't need more than that
  132. bone_anim_data = [[], [], [], [], [], [], [], [], []]
  133. ###########################
  134. # read bone animation table
  135. ###########################
  136. for i in range(9):
  137. #
  138. line = f.readline()
  139. row_data = line.split(',')
  140. # if row_data's length is not equal to the length of
  141. # csv_keyframe_numbers + 3 fill it with empty strings to match said length
  142. while (len(row_data) != (len(csv_keyframe_numbers) + 3)):
  143. row_data.append("")
  144. ############################################################
  145. # copy the keyframe values from row_data into bone_anim_data
  146. ############################################################
  147. for j in range(len(row_data)):
  148. #
  149. # first 3 elements of row_data are skipped
  150. # example: Joint 0, Scale X:, Linear, ...
  151. if (j < 3):
  152. continue
  153. # if there is no animation value for the bone on the
  154. # current keyframe data append None to said position
  155. # otherwise append the value
  156. if (row_data[j] == "" or row_data[j] == '\n'):
  157. bone_anim_data[i].append(None)
  158. else:
  159. bone_anim_data[i].append(float(row_data[j]))
  160. #
  161. #
  162. ####################################
  163. # write bone animation table to bone
  164. # only go through the keyframes
  165. # pointed to in csv_keyframe_numbers
  166. ####################################
  167. for k in range(len(csv_keyframe_numbers)):
  168. #
  169. # set frame on Blender
  170. scene.frame_set(csv_keyframe_numbers[k])
  171. # apply scale values X-Y-Z
  172. if (bone_anim_data[0][k] != None):
  173. pose_bone.scale[0] = bone_anim_data[0][k]
  174. pose_bone.keyframe_insert(data_path = 'scale', index = 0)
  175. if (bone_anim_data[1][k] != None):
  176. pose_bone.scale[1] = bone_anim_data[1][k]
  177. pose_bone.keyframe_insert(data_path = 'scale', index = 1)
  178. if (bone_anim_data[2][k] != None):
  179. pose_bone.scale[2] = bone_anim_data[2][k]
  180. pose_bone.keyframe_insert(data_path = 'scale', index = 2)
  181. # apply rotation values (converted to radians)
  182. if (bone_anim_data[3][k] != None):
  183. pose_bone.rotation_euler[0] = math.radians(bone_anim_data[3][k])
  184. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 0)
  185. if (bone_anim_data[4][k] != None):
  186. pose_bone.rotation_euler[1] = math.radians(bone_anim_data[4][k])
  187. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 1)
  188. if (bone_anim_data[5][k] != None):
  189. pose_bone.rotation_euler[2] = math.radians(bone_anim_data[5][k])
  190. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 2)
  191. # apply translation values (divided by 100 because 1 GU is 100 meters)
  192. if (bone_anim_data[6][k] != None):
  193. pose_bone.location[0] = bone_anim_data[6][k] / 100
  194. pose_bone.keyframe_insert(data_path = 'location', index = 0)
  195. if (bone_anim_data[7][k] != None):
  196. pose_bone.location[1] = bone_anim_data[7][k] / 100
  197. pose_bone.keyframe_insert(data_path = 'location', index = 1)
  198. if (bone_anim_data[8][k] != None):
  199. pose_bone.location[2] = bone_anim_data[8][k] / 100
  200. pose_bone.keyframe_insert(data_path = 'location', index = 2)
  201. #
  202. #
  203. #
  204. ###########################################################################
  205. ###########################################################################
  206. # import type "rest pose"
  207. # in here I need to calculate the animation values for the reference system
  208. # defined by the bone's rest pose as the BCK CSVs store animation data of a
  209. # bone with respect to its parent. Conversion from a reference system to
  210. # another can be done easily with matrix multiplication but the rotation
  211. # data must be preprocessed first (angles that are outside the -180/+180
  212. # degree range are lost in the conversion process)
  213. ###########################################################################
  214. ###########################################################################
  215. else:
  216. #
  217. # read the CSV from the start again
  218. # to import the animation values
  219. f = open(filepath, 'r', encoding='utf-8')
  220. line = f.readline()
  221. # first line of the CSV
  222. csv_first_line = line.split(',')
  223. animation_length = int(csv_first_line[1])
  224. # get the animation last frame and set it in blender
  225. bpy.data.scenes["Scene"].frame_end = int(csv_first_line[1])
  226. # the next line comes with the notable keyframes used in the animation
  227. line = f.readline()
  228. # get all keyframe numbers
  229. csv_keyframe_numbers = re.findall('[0-9]+', line)
  230. csv_keyframe_numbers = [int(string) for string in csv_keyframe_numbers]
  231. ###############################################################
  232. # in the next loop starts the bone animation data table reading
  233. # loop through every bone
  234. ###############################################################
  235. for bone_number in range(bone_count):
  236. # get pose.bone and data.bone
  237. pose_bone = armature.pose.bones[bone_number]
  238. data_bone = armature.data.bones[bone_number]
  239. print("Reading/Writing animation for bone: %s" % (pose_bone.name))
  240. # set bone rotation mode to Extrinsic Euler XYZ
  241. pose_bone.rotation_mode = 'XYZ'
  242. # bone_anim_data will hold the bone frame animation (all frames)
  243. # data for a single bone from the CSV file as follows
  244. # row 1 --> X scaling
  245. # row 2 --> Y scaling
  246. # row 3 --> Z scaling
  247. # row 4 --> X rotation
  248. # row 5 --> Y rotation
  249. # row 6 --> Z rotation
  250. # row 7 --> X translation
  251. # row 8 --> Y translation
  252. # row 9 --> Z translation
  253. # already initialized with 9 rows as I don't need more than that
  254. bone_anim_data = [[], [], [], [], [], [], [], [], []]
  255. ###########################
  256. # read bone animation table
  257. ###########################
  258. for i in range(9):
  259. #
  260. line = f.readline()
  261. row_data = line.split(',')
  262. # if row_data's length is not equal to the length of
  263. # csv_keyframe_numbers + 3 fill it with empty strings to match said length
  264. while (len(row_data) != (len(csv_keyframe_numbers) + 3)):
  265. row_data.append("")
  266. ############################################################
  267. # copy the keyframe values from row_data into bone_anim_data
  268. # and make bone_anim_data hold all frame values for the bone
  269. ############################################################
  270. # k will be used to go through csv_keyframe_numbers
  271. # and also through row_data as its length is
  272. # (len(csv_keyframe_numbers) + 3)
  273. j = 0
  274. for k in range(animation_length + 1):
  275. #
  276. # Note: first 3 elements of row_data are skipped
  277. # example: Joint 0, Scale X:, Linear, ...
  278. # if the animation frame isn't a keyframe append None to
  279. # bone_anim_data[i] and go to the next frame
  280. if (k != csv_keyframe_numbers[j]):
  281. bone_anim_data[i].append(None)
  282. continue
  283. # if it is a keyframe advance to the next keyframe
  284. # on csv_keyframe_numbers
  285. # if there is no animation value for the bone on the
  286. # current keyframe data append None to said position
  287. # otherwise append the value
  288. if (row_data[j + 3] == "" or row_data[j + 3] == '\n'):
  289. bone_anim_data[i].append(None)
  290. else:
  291. bone_anim_data[i].append(float(row_data[j + 3]))
  292. # advance in row_data
  293. j = j + 1
  294. #
  295. #
  296. ########################################################
  297. # modify bone_anim_data rotation animation values
  298. # so that the angles on it are between -180/+180
  299. # to avoid visual animation data loss
  300. # convert_rot_anim_to_180() will be an external function
  301. # the process of converting the animation rotation on all
  302. # axises into the -180/180 degree range can create new
  303. # keyframes to the aniamtion and they will be appended
  304. # at the end of csv_keyframe_numbers so that those
  305. # keyframes are processed after the main ones are done
  306. ########################################################
  307. convert_rot_anim_to_180(bone_anim_data[3], csv_keyframe_numbers)
  308. convert_rot_anim_to_180(bone_anim_data[4], csv_keyframe_numbers)
  309. convert_rot_anim_to_180(bone_anim_data[5], csv_keyframe_numbers)
  310. ####################################
  311. # write bone animation table to bone
  312. # only go through the keyframes
  313. # pointed to in csv_keyframe_numbers
  314. ####################################
  315. # k is used to go through csv_keyframe_numbers
  316. # kf_num is used to go through bone_anim_data
  317. for k in range(len(csv_keyframe_numbers)):
  318. #
  319. # get keyframe number
  320. kf_num = csv_keyframe_numbers[k]
  321. # set keyframe on Blender
  322. scene.frame_set(kf_num)
  323. # - get animation data
  324. # - convert animation to rest pose reference system
  325. # find all 9 animation properties with linear interpolation if needed
  326. # (for now) the final goal is to only keep the keyframes from the BCK without
  327. # having to assign a keyframe for each frame of the animation in Blender
  328. # anim_temp will be used to hold the 9 animation
  329. # property data as it is read/calculated
  330. anim_temp = []
  331. ########################################################
  332. # find scale values in ignore rest pose reference system
  333. ########################################################
  334. #########
  335. # Scale X
  336. if (bone_anim_data[0][kf_num] != None):
  337. anim_temp.append(bone_anim_data[0][kf_num])
  338. else:
  339. # find left and right values (store in temp array)
  340. a = find_left_right(bone_anim_data[0], kf_num)
  341. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  342. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear"))
  343. #########
  344. # Scale Y
  345. if (bone_anim_data[1][kf_num] != None):
  346. anim_temp.append(bone_anim_data[1][kf_num])
  347. else:
  348. # find left and right values (store in temp array)
  349. a = find_left_right(bone_anim_data[1], kf_num)
  350. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  351. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear"))
  352. #########
  353. # Scale Z
  354. if (bone_anim_data[2][kf_num] != None):
  355. anim_temp.append(bone_anim_data[2][kf_num])
  356. else:
  357. # find left and right values (store in temp array)
  358. a = find_left_right(bone_anim_data[2], kf_num)
  359. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  360. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear"))
  361. ########################################################################
  362. # find rotation values in ignore rest pose reference system (in radians)
  363. ########################################################################
  364. ############
  365. # Rotation X
  366. if (bone_anim_data[3][kf_num] != None):
  367. anim_temp.append(math.radians(bone_anim_data[3][kf_num]))
  368. else:
  369. # find left and right values (store in temp array)
  370. a = find_left_right(bone_anim_data[3], kf_num)
  371. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  372. anim_temp.append(math.radians(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear")))
  373. ############
  374. # Rotation Y
  375. if (bone_anim_data[4][kf_num] != None):
  376. anim_temp.append(math.radians(bone_anim_data[4][kf_num]))
  377. else:
  378. # find left and right values (store in temp array)
  379. a = find_left_right(bone_anim_data[4], kf_num)
  380. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  381. anim_temp.append(math.radians(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear")))
  382. ############
  383. # Rotation Z
  384. if (bone_anim_data[5][kf_num] != None):
  385. anim_temp.append(math.radians(bone_anim_data[5][kf_num]))
  386. else:
  387. # find left and right values (store in temp array)
  388. a = find_left_right(bone_anim_data[5], kf_num)
  389. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  390. anim_temp.append(math.radians(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear")))
  391. ##############################################################
  392. # find translation values in ignore rest pose reference system
  393. # divided by 100 because 1 GU is 100 meters
  394. ##############################################################
  395. ###############
  396. # Translation X
  397. if (bone_anim_data[6][kf_num] != None):
  398. anim_temp.append(bone_anim_data[6][kf_num] / 100)
  399. else:
  400. # find left and right values (store in temp array)
  401. a = find_left_right(bone_anim_data[6], kf_num)
  402. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  403. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear") / 100)
  404. ###############
  405. # Translation Y
  406. if (bone_anim_data[7][kf_num] != None):
  407. anim_temp.append(bone_anim_data[7][kf_num] / 100)
  408. else:
  409. # find left and right values (store in temp array)
  410. a = find_left_right(bone_anim_data[7], kf_num)
  411. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  412. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear") / 100)
  413. ###############
  414. # Translation Z
  415. if (bone_anim_data[8][kf_num] != None):
  416. anim_temp.append(bone_anim_data[8][kf_num] / 100)
  417. else:
  418. # find left and right values (store in temp array)
  419. a = find_left_right(bone_anim_data[8], kf_num)
  420. # interpolate ^ [l_val_pos, l_val, r_val_pos, r_val]
  421. anim_temp.append(interpolate(a[0], a[1], a[2], a[3], kf_num, None, "linear") / 100)
  422. ###################################################
  423. # create the animation matrix related to the ignore
  424. # rest pose (irp) transformation matrix (T * R * S)
  425. ###################################################
  426. anim_irp_mat = calc_translation_matrix(anim_temp[6], anim_temp[7], anim_temp[8]) * calc_rotation_matrix(anim_temp[3], anim_temp[4], anim_temp[5]) * calc_scale_matrix(anim_temp[0], anim_temp[1], anim_temp[2])
  427. #########################################################
  428. # calculate the animation matrix related to the rest pose
  429. # rest pose matrix of the bone is in the data_bone
  430. # the first bone has no parent
  431. #########################################################
  432. if (bone_number == 0):
  433. anim_rp_mat = anim_irp_mat
  434. else:
  435. anim_rp_mat = (data_bone.parent.matrix_local.inverted() * data_bone.matrix_local).inverted() * anim_irp_mat
  436. #####################################
  437. # extract calculated animation values
  438. #####################################
  439. # Scaling
  440. bone_scale = anim_rp_mat.to_scale()
  441. # Rotation (Extrinsic Euler XYZ)
  442. bone_rotation = anim_rp_mat.to_euler('XYZ')
  443. # Translation
  444. bone_translation = anim_rp_mat.to_translation()
  445. ####################################################
  446. # apply the respective keyframe values to the bone
  447. # if any of the values on scale/rotation/translation
  448. # is different than None create a keyframe for all
  449. # XYZ axises on said scale/rotation/translation
  450. # animation property. Will keep the individual
  451. # keyframe assignment just in case it is needed in
  452. # a future program logic update
  453. ####################################################
  454. ########################
  455. # apply scale values XYZ
  456. if (bone_anim_data[0][kf_num] != None
  457. or
  458. bone_anim_data[1][kf_num] != None
  459. or
  460. bone_anim_data[2][kf_num] != None):
  461. pose_bone.scale[0] = bone_scale[0]
  462. pose_bone.keyframe_insert(data_path = 'scale', index = 0)
  463. pose_bone.scale[1] = bone_scale[1]
  464. pose_bone.keyframe_insert(data_path = 'scale', index = 1)
  465. pose_bone.scale[2] = bone_scale[2]
  466. pose_bone.keyframe_insert(data_path = 'scale', index = 2)
  467. ###########################
  468. # apply rotation values XYZ
  469. if (bone_anim_data[3][kf_num] != None
  470. or
  471. bone_anim_data[4][kf_num] != None
  472. or
  473. bone_anim_data[5][kf_num] != None):
  474. pose_bone.rotation_euler[0] = bone_rotation[0]
  475. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 0)
  476. pose_bone.rotation_euler[1] = bone_rotation[1]
  477. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 1)
  478. pose_bone.rotation_euler[2] = bone_rotation[2]
  479. pose_bone.keyframe_insert(data_path = 'rotation_euler', index = 2)
  480. ##############################
  481. # apply translation values XYZ
  482. if (bone_anim_data[6][kf_num] != None
  483. or
  484. bone_anim_data[7][kf_num] != None
  485. or
  486. bone_anim_data[8][kf_num] != None):
  487. pose_bone.location[0] = bone_translation[0]
  488. pose_bone.keyframe_insert(data_path = 'location', index = 0)
  489. pose_bone.location[1] = bone_translation[1]
  490. pose_bone.keyframe_insert(data_path = 'location', index = 1)
  491. pose_bone.location[2] = bone_translation[2]
  492. pose_bone.keyframe_insert(data_path = 'location', index = 2)
  493. #
  494. #
  495. #
  496. ######################################
  497. # make all interpolation curves linear
  498. # loop through each curve and through
  499. # each of the curve's keyframe
  500. curves = bpy.context.active_object.animation_data.action.fcurves
  501. for curve in curves:
  502. for keyframe in curve.keyframe_points:
  503. keyframe.interpolation = 'LINEAR'
  504. # importer end
  505. return {'FINISHED'}
  506. #
  507. #################################################
  508. # Stuff down is for the menu appending
  509. # of the importer to work plus some setting stuff
  510. # comes from a Blender importer template
  511. #################################################
  512. from bpy_extras.io_utils import ExportHelper
  513. from bpy.props import StringProperty, BoolProperty, EnumProperty
  514. from bpy.types import Operator
  515. class Import_CSV_BCK(Operator, ExportHelper):
  516. #
  517. """Import a CSV file from J3D Animation Editor of the BCK animation type. Armature to which the animation must be applied must be the only armature in scene and must be the correct one for the animation"""
  518. bl_idname = "import_scene.csv_bck"
  519. bl_label = "Import CSV of BCK (from J3D Anim Editor)"
  520. filename_ext = ".csv"
  521. filter_glob = StringProperty(
  522. default="*.csv",
  523. options={'HIDDEN'},
  524. maxlen=255,
  525. )
  526. import_type = BoolProperty( name = "Ignore Rest Pose",
  527. description = "Ignore all bone's rest poses and apply animations as SMG does. Modifies the bone's original rest pose.",
  528. default = False,
  529. )
  530. def execute(self, context):
  531. return read_csv_bck(context, self.filepath, self.import_type)
  532. #
  533. def menu_import_csv_bck(self, context):
  534. self.layout.operator(Import_CSV_BCK.bl_idname, text="CSV of BCK (from J3D Animation Editor) (.csv)")
  535. bpy.utils.register_class(Import_CSV_BCK)
  536. bpy.types.INFO_MT_file_import.append(menu_import_csv_bck)
  537. # test call
  538. bpy.ops.import_scene.csv_bck('INVOKE_DEFAULT')