package_level.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from sys import modules
  2. from math import floor
  3. from mathutils import Euler, Matrix
  4. from bpy import app
  5. from time import strftime
  6. MAX_FLOAT_PRECISION_INT = 4
  7. MAX_FLOAT_PRECISION = '%.' + str(MAX_FLOAT_PRECISION_INT) + 'f'
  8. VERTEX_OUTPUT_PER_LINE = 50
  9. STRIP_LEADING_ZEROS_DEFAULT = False # false for .babylon
  10. #===============================================================================
  11. # module level formatting methods, called from multiple classes
  12. #===============================================================================
  13. def get_title():
  14. bl_info = get_bl_info()
  15. return bl_info['name'] + ' ver ' + format_exporter_version(bl_info)
  16. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  17. def format_exporter_version(bl_info = None):
  18. if bl_info is None:
  19. bl_info = get_bl_info()
  20. exporterVersion = bl_info['version']
  21. return str(exporterVersion[0]) + '.' + str(exporterVersion[1]) + '.' + str(exporterVersion[2])
  22. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  23. def blenderMajorMinorVersion():
  24. # in form of '2.77 (sub 0)'
  25. split1 = app.version_string.partition('.')
  26. major = split1[0]
  27. split2 = split1[2].partition(' ')
  28. minor = split2[0]
  29. return float(major + '.' + minor)
  30. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  31. def verify_min_blender_version():
  32. reqd = get_bl_info()['blender']
  33. # in form of '2.77 (sub 0)'
  34. split1 = app.version_string.partition('.')
  35. major = int(split1[0])
  36. if reqd[0] > major: return False
  37. split2 = split1[2].partition(' ')
  38. minor = int(split2[0])
  39. if reqd[1] > minor: return False
  40. split3 = split2[2].partition(' ')
  41. revision = int(split3[2][:1])
  42. if reqd[2] > revision: return False
  43. return True
  44. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  45. def getNameSpace(filepathMinusExtension):
  46. # assign nameSpace, based on OS
  47. if filepathMinusExtension.find('\\') != -1:
  48. return legal_js_identifier(filepathMinusExtension.rpartition('\\')[2])
  49. else:
  50. return legal_js_identifier(filepathMinusExtension.rpartition('/')[2])
  51. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  52. def getLayer(obj):
  53. # empties / nodes do not have layers
  54. if not hasattr(object, 'layers') : return -1;
  55. for idx, layer in enumerate(obj.layers):
  56. if layer:
  57. return idx
  58. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  59. # a class for getting the module name, exporter version, & reqd blender version in get_bl_info()
  60. class dummy: pass
  61. def get_bl_info():
  62. # .__module__ is the 'name of package.module', so strip after dot
  63. packageName = dummy.__module__.partition('.')[0]
  64. return modules.get(packageName).bl_info
  65. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  66. def legal_js_identifier(input):
  67. out = ''
  68. prefix = ''
  69. for char in input:
  70. if len(out) == 0:
  71. if char in '0123456789':
  72. # cannot take the chance that leading numbers being chopped of cause name conflicts, e.g (01.R & 02.R)
  73. prefix += char
  74. continue
  75. elif char.upper() not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
  76. continue
  77. legal = char if char.upper() in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' else '_'
  78. out += legal
  79. if len(prefix) > 0:
  80. out += '_' + prefix
  81. return out
  82. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  83. def format_f(num, stripLeadingZero = STRIP_LEADING_ZEROS_DEFAULT):
  84. s = MAX_FLOAT_PRECISION % num # rounds to N decimal places while changing to string
  85. s = s.rstrip('0') # strip trailing zeroes
  86. s = s.rstrip('.') # strip trailing .
  87. s = '0' if s == '-0' else s # nuke -0
  88. if stripLeadingZero:
  89. asNum = float(s)
  90. if asNum != 0 and asNum > -1 and asNum < 1:
  91. if asNum < 0:
  92. s = '-' + s[2:]
  93. else:
  94. s = s[1:]
  95. return s
  96. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  97. def format_matrix4(matrix):
  98. tempMatrix = matrix.copy()
  99. tempMatrix.transpose()
  100. ret = ''
  101. first = True
  102. for vect in tempMatrix:
  103. if (first != True):
  104. ret +=','
  105. first = False;
  106. ret += format_f(vect[0]) + ',' + format_f(vect[1]) + ',' + format_f(vect[2]) + ',' + format_f(vect[3])
  107. return ret
  108. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  109. def format_array3(array):
  110. return format_f(array[0]) + ',' + format_f(array[1]) + ',' + format_f(array[2])
  111. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  112. def format_array(array, indent = ''):
  113. ret = ''
  114. first = True
  115. nOnLine = 0
  116. for element in array:
  117. if (first != True):
  118. ret +=','
  119. first = False;
  120. ret += format_f(element)
  121. nOnLine += 1
  122. if nOnLine >= VERTEX_OUTPUT_PER_LINE:
  123. ret += '\n' + indent
  124. nOnLine = 0
  125. return ret
  126. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  127. def format_color(color):
  128. return format_f(color.r) + ',' + format_f(color.g) + ',' + format_f(color.b)
  129. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  130. def format_vector(vector, switchYZ = True):
  131. return format_f(vector.x) + ',' + format_f(vector.z) + ',' + format_f(vector.y) if switchYZ else format_f(vector.x) + ',' + format_f(vector.y) + ',' + format_f(vector.z)
  132. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  133. def format_vector_array(vectorArray, indent = ''):
  134. ret = ''
  135. first = True
  136. nOnLine = 0
  137. for vector in vectorArray:
  138. if (first != True):
  139. ret +=','
  140. first = False;
  141. ret += format_vector(vector)
  142. nOnLine += 3
  143. if nOnLine >= VERTEX_OUTPUT_PER_LINE:
  144. ret += '\n' + indent
  145. nOnLine = 0
  146. return ret
  147. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  148. def format_quaternion(quaternion):
  149. return format_f(quaternion.x) + ',' + format_f(quaternion.z) + ',' + format_f(quaternion.y) + ',' + format_f(-quaternion.w)
  150. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  151. def format_int(int):
  152. candidate = str(int) # when int string of an int
  153. if '.' in candidate:
  154. return format_f(floor(int)) # format_f removes un-neccessary precision
  155. else:
  156. return candidate
  157. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  158. def format_bool(bool):
  159. if bool:
  160. return 'true'
  161. else:
  162. return 'false'
  163. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  164. def post_rotate_quaternion(quat, angle):
  165. post = Euler((angle, 0.0, 0.0)).to_matrix()
  166. mqtn = quat.to_matrix()
  167. quat = (mqtn*post).to_quaternion()
  168. return quat
  169. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  170. def scale_vector(vector, mult, xOffset = 0):
  171. ret = vector.copy()
  172. ret.x *= mult
  173. ret.x += xOffset
  174. ret.z *= mult
  175. ret.y *= mult
  176. return ret
  177. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  178. def same_matrix4(matA, matB):
  179. if(matA is None or matB is None): return False
  180. if (len(matA) != len(matB)): return False
  181. for i in range(len(matA)):
  182. if (format_f(matA[i][0]) != format_f(matB[i][0]) or
  183. format_f(matA[i][1]) != format_f(matB[i][1]) or
  184. format_f(matA[i][2]) != format_f(matB[i][2]) or
  185. format_f(matA[i][3]) != format_f(matB[i][3]) ):
  186. return False
  187. return True
  188. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  189. def same_vertex(vertA, vertB):
  190. if vertA is None or vertB is None: return False
  191. if (format_f(vertA.x) != format_f(vertB.x) or
  192. format_f(vertA.y) != format_f(vertB.y) or
  193. format_f(vertA.z) != format_f(vertB.z) ):
  194. return False
  195. return True
  196. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  197. def same_array(arrayA, arrayB):
  198. if(arrayA is None or arrayB is None): return False
  199. if len(arrayA) != len(arrayB): return False
  200. for i in range(len(arrayA)):
  201. if format_f(arrayA[i]) != format_f(arrayB[i]) : return False
  202. return True
  203. #===============================================================================
  204. # module level methods for writing JSON (.babylon) files
  205. #===============================================================================
  206. def write_matrix4(file_handler, name, matrix):
  207. file_handler.write(',"' + name + '":[' + format_matrix4(matrix) + ']')
  208. def write_array(file_handler, name, array):
  209. file_handler.write('\n,"' + name + '":[' + format_array(array) + ']')
  210. def write_array3(file_handler, name, array):
  211. file_handler.write(',"' + name + '":[' + format_array3(array) + ']')
  212. def write_color(file_handler, name, color):
  213. file_handler.write(',"' + name + '":[' + format_color(color) + ']')
  214. def write_vector(file_handler, name, vector, switchYZ = True):
  215. file_handler.write(',"' + name + '":[' + format_vector(vector, switchYZ) + ']')
  216. def write_vector_array(file_handler, name, vectorArray):
  217. file_handler.write('\n,"' + name + '":[' + format_vector_array(vectorArray) + ']')
  218. def write_quaternion(file_handler, name, quaternion):
  219. file_handler.write(',"' + name +'":[' + format_quaternion(quaternion) + ']')
  220. def write_string(file_handler, name, string, noComma = False):
  221. if noComma == False:
  222. file_handler.write(',')
  223. file_handler.write('"' + name + '":"' + string + '"')
  224. def write_float(file_handler, name, float):
  225. file_handler.write(',"' + name + '":' + format_f(float))
  226. def write_int(file_handler, name, int, noComma = False):
  227. if noComma == False:
  228. file_handler.write(',')
  229. file_handler.write('"' + name + '":' + format_int(int))
  230. def write_bool(file_handler, name, bool, noComma = False):
  231. if noComma == False:
  232. file_handler.write(',')
  233. file_handler.write('"' + name + '":' + format_bool(bool))