__init__.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. import os
  19. import json
  20. import logging
  21. import bpy
  22. from bpy_extras.io_utils import ExportHelper
  23. from bpy.props import (
  24. EnumProperty,
  25. BoolProperty,
  26. FloatProperty,
  27. IntProperty,
  28. StringProperty
  29. )
  30. from . import constants
  31. logging.basicConfig(
  32. format='%(levelname)s:THREE:%(message)s',
  33. level=logging.DEBUG)
  34. bl_info = {
  35. 'name': "Three.js Format",
  36. 'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa, tschw, jackcaron, bhouston",
  37. 'version': (1, 5, 0),
  38. 'blender': (2, 74, 0),
  39. 'location': "File > Export",
  40. 'description': "Export Three.js formatted JSON files.",
  41. 'warning': "Importer not included.",
  42. 'wiki_url': "https://github.com/mrdoob/three.js/tree/"\
  43. "master/utils/exporters/blender",
  44. 'tracker_url': "https://github.com/mrdoob/three.js/issues",
  45. 'category': 'Import-Export'
  46. }
  47. def _geometry_types():
  48. """The valid geometry types that are supported by Three.js
  49. :return: list of tuples
  50. """
  51. keys = (constants.GLOBAL,
  52. constants.GEOMETRY,
  53. constants.BUFFER_GEOMETRY)
  54. types = []
  55. for key in keys:
  56. types.append((key, key.title(), key))
  57. return types
  58. bpy.types.Mesh.THREE_geometry_type = EnumProperty(
  59. name="Geometry type",
  60. description="Geometry type",
  61. items=_geometry_types(),
  62. default=constants.GLOBAL)
  63. class ThreeMesh(bpy.types.Panel):
  64. """Creates custom properties on a mesh node"""
  65. bl_label = 'THREE'
  66. bl_space_type = 'PROPERTIES'
  67. bl_region_type = 'WINDOW'
  68. bl_context = 'data'
  69. def draw(self, context):
  70. """
  71. :param context:
  72. """
  73. row = self.layout.row()
  74. if context.mesh:
  75. row.prop(context.mesh,
  76. 'THREE_geometry_type',
  77. text="Type")
  78. def _blending_types(index):
  79. """Supported blending types for Three.js
  80. :param index:
  81. :type index: int
  82. :returns: tuple if types (str, str, str)
  83. """
  84. types = (constants.BLENDING_TYPES.NONE,
  85. constants.BLENDING_TYPES.NORMAL,
  86. constants.BLENDING_TYPES.ADDITIVE,
  87. constants.BLENDING_TYPES.SUBTRACTIVE,
  88. constants.BLENDING_TYPES.MULTIPLY,
  89. constants.BLENDING_TYPES.CUSTOM)
  90. return (types[index], types[index], types[index])
  91. bpy.types.Material.THREE_blending_type = EnumProperty(
  92. name="Blending type",
  93. description="Blending type",
  94. items=[_blending_types(x) for x in range(6)],
  95. default=constants.BLENDING_TYPES.NORMAL)
  96. bpy.types.Material.THREE_depth_write = BoolProperty(default=True)
  97. bpy.types.Material.THREE_depth_test = BoolProperty(default=True)
  98. bpy.types.Material.THREE_double_sided = BoolProperty(default=False)
  99. class ThreeMaterial(bpy.types.Panel):
  100. """Adds custom properties to the Materials of an object"""
  101. bl_label = 'THREE'
  102. bl_space_type = 'PROPERTIES'
  103. bl_region_type = 'WINDOW'
  104. bl_context = 'material'
  105. def draw(self, context):
  106. """
  107. :param context:
  108. """
  109. layout = self.layout
  110. mat = context.material
  111. if mat is not None:
  112. row = layout.row()
  113. row.label(text="Selected material: %s" % mat.name)
  114. row = layout.row()
  115. row.prop(mat, 'THREE_blending_type',
  116. text="Blending type")
  117. row = layout.row()
  118. row.prop(mat, 'THREE_depth_write',
  119. text="Enable depth writing")
  120. row = layout.row()
  121. row.prop(mat, 'THREE_depth_test',
  122. text="Enable depth testing")
  123. row = layout.row()
  124. row.prop(mat, 'THREE_double_sided',
  125. text="Double-sided")
  126. def _mag_filters(index):
  127. """Three.js mag filters
  128. :param index:
  129. :type index: int
  130. :returns: tuple with the filter values
  131. """
  132. types = (constants.LINEAR_FILTERS.LINEAR,
  133. constants.NEAREST_FILTERS.NEAREST)
  134. return (types[index], types[index], types[index])
  135. bpy.types.Texture.THREE_mag_filter = EnumProperty(
  136. name="Mag Filter",
  137. items=[_mag_filters(x) for x in range(2)],
  138. default=constants.LINEAR_FILTERS.LINEAR)
  139. def _min_filters(index):
  140. """Three.js min filters
  141. :param index:
  142. :type index: int
  143. :returns: tuple with the filter values
  144. """
  145. types = (constants.LINEAR_FILTERS.LINEAR,
  146. constants.LINEAR_FILTERS.MIP_MAP_NEAREST,
  147. constants.LINEAR_FILTERS.MIP_MAP_LINEAR,
  148. constants.NEAREST_FILTERS.NEAREST,
  149. constants.NEAREST_FILTERS.MIP_MAP_NEAREST,
  150. constants.NEAREST_FILTERS.MIP_MAP_LINEAR)
  151. return (types[index], types[index], types[index])
  152. bpy.types.Texture.THREE_min_filter = EnumProperty(
  153. name="Min Filter",
  154. items=[_min_filters(x) for x in range(6)],
  155. default=constants.LINEAR_FILTERS.MIP_MAP_LINEAR)
  156. def _mapping(index):
  157. """Three.js texture mappings types
  158. :param index:
  159. :type index: int
  160. :returns: tuple with the mapping values
  161. """
  162. types = (constants.MAPPING_TYPES.UV,
  163. constants.MAPPING_TYPES.CUBE_REFLECTION,
  164. constants.MAPPING_TYPES.CUBE_REFRACTION,
  165. constants.MAPPING_TYPES.SPHERICAL_REFLECTION)
  166. return (types[index], types[index], types[index])
  167. bpy.types.Texture.THREE_mapping = EnumProperty(
  168. name="Mapping",
  169. items=[_mapping(x) for x in range(4)],
  170. default=constants.MAPPING_TYPES.UV)
  171. class ThreeTexture(bpy.types.Panel):
  172. """Adds custom properties to a texture"""
  173. bl_label = 'THREE'
  174. bl_space_type = 'PROPERTIES'
  175. bl_region_type = 'WINDOW'
  176. bl_context = 'texture'
  177. #@TODO: possible to make cycles compatible?
  178. def draw(self, context):
  179. """
  180. :param context:
  181. """
  182. layout = self.layout
  183. tex = context.texture
  184. if tex is not None:
  185. row = layout.row()
  186. row.prop(tex, 'THREE_mapping', text="Mapping")
  187. row = layout.row()
  188. row.prop(tex, 'THREE_mag_filter', text="Mag Filter")
  189. row = layout.row()
  190. row.prop(tex, 'THREE_min_filter', text="Min Filter")
  191. bpy.types.Object.THREE_export = bpy.props.BoolProperty(default=True)
  192. class ThreeObject(bpy.types.Panel):
  193. """Adds custom properties to an object"""
  194. bl_label = 'THREE'
  195. bl_space_type = 'PROPERTIES'
  196. bl_region_type = 'WINDOW'
  197. bl_context = 'object'
  198. def draw(self, context):
  199. """
  200. :param context:
  201. """
  202. layout = self.layout
  203. obj = context.object
  204. row = layout.row()
  205. row.prop(obj, 'THREE_export', text='Export')
  206. class ThreeExportSettings(bpy.types.Operator):
  207. """Save the current export settings (gets saved in .blend)"""
  208. bl_label = "Save Settings"
  209. bl_idname = "scene.three_export_settings_set"
  210. def execute(self, context):
  211. cycles = context.scene.cycles
  212. cycles.use_samples_final = True
  213. context.scene[constants.EXPORT_SETTINGS_KEY] = set_settings(context.active_operator.properties)
  214. self.report({"INFO"}, "Three Export Settings Saved")
  215. return {"FINISHED"}
  216. def restore_export_settings(properties, settings):
  217. """Restore the settings
  218. :param properties:
  219. """
  220. ## Geometry {
  221. properties.option_vertices = settings.get(
  222. constants.VERTICES,
  223. constants.EXPORT_OPTIONS[constants.VERTICES])
  224. properties.option_faces = settings.get(
  225. constants.FACES,
  226. constants.EXPORT_OPTIONS[constants.FACES])
  227. properties.option_normals = settings.get(
  228. constants.NORMALS,
  229. constants.EXPORT_OPTIONS[constants.NORMALS])
  230. properties.option_skinning = settings.get(
  231. constants.SKINNING,
  232. constants.EXPORT_OPTIONS[constants.SKINNING])
  233. properties.option_bones = settings.get(
  234. constants.BONES,
  235. constants.EXPORT_OPTIONS[constants.BONES])
  236. properties.option_influences = settings.get(
  237. constants.INFLUENCES_PER_VERTEX,
  238. constants.EXPORT_OPTIONS[constants.INFLUENCES_PER_VERTEX])
  239. properties.option_apply_modifiers = settings.get(
  240. constants.APPLY_MODIFIERS,
  241. constants.EXPORT_OPTIONS[constants.APPLY_MODIFIERS])
  242. properties.option_extra_vgroups = settings.get(
  243. constants.EXTRA_VGROUPS,
  244. constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
  245. properties.option_geometry_type = settings.get(
  246. constants.GEOMETRY_TYPE,
  247. constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
  248. properties.option_index_type = settings.get(
  249. constants.INDEX_TYPE,
  250. constants.EXPORT_OPTIONS[constants.INDEX_TYPE])
  251. ## }
  252. ## Materials {
  253. properties.option_materials = settings.get(
  254. constants.MATERIALS,
  255. constants.EXPORT_OPTIONS[constants.MATERIALS])
  256. properties.option_uv_coords = settings.get(
  257. constants.UVS,
  258. constants.EXPORT_OPTIONS[constants.UVS])
  259. properties.option_face_materials = settings.get(
  260. constants.FACE_MATERIALS,
  261. constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
  262. properties.option_maps = settings.get(
  263. constants.MAPS,
  264. constants.EXPORT_OPTIONS[constants.MAPS])
  265. properties.option_colors = settings.get(
  266. constants.COLORS,
  267. constants.EXPORT_OPTIONS[constants.COLORS])
  268. properties.option_mix_colors = settings.get(
  269. constants.MIX_COLORS,
  270. constants.EXPORT_OPTIONS[constants.MIX_COLORS])
  271. ## }
  272. ## Settings {
  273. properties.option_scale = settings.get(
  274. constants.SCALE,
  275. constants.EXPORT_OPTIONS[constants.SCALE])
  276. properties.option_round_off = settings.get(
  277. constants.ENABLE_PRECISION,
  278. constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
  279. properties.option_round_value = settings.get(
  280. constants.PRECISION,
  281. constants.EXPORT_OPTIONS[constants.PRECISION])
  282. properties.option_custom_properties = settings.get(
  283. constants.CUSTOM_PROPERTIES,
  284. constants.EXPORT_OPTIONS[constants.CUSTOM_PROPERTIES])
  285. properties.option_logging = settings.get(
  286. constants.LOGGING,
  287. constants.EXPORT_OPTIONS[constants.LOGGING])
  288. properties.option_compression = settings.get(
  289. constants.COMPRESSION,
  290. constants.NONE)
  291. properties.option_indent = settings.get(
  292. constants.INDENT,
  293. constants.EXPORT_OPTIONS[constants.INDENT])
  294. properties.option_export_textures = settings.get(
  295. constants.EXPORT_TEXTURES,
  296. constants.EXPORT_OPTIONS[constants.EXPORT_TEXTURES])
  297. properties.option_embed_textures = settings.get(
  298. constants.EMBED_TEXTURES,
  299. constants.EXPORT_OPTIONS[constants.EMBED_TEXTURES])
  300. properties.option_texture_folder = settings.get(
  301. constants.TEXTURE_FOLDER,
  302. constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER])
  303. properties.option_embed_animation = settings.get(
  304. constants.EMBED_ANIMATION,
  305. constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
  306. ## }
  307. ## Scene {
  308. properties.option_export_scene = settings.get(
  309. constants.SCENE,
  310. constants.EXPORT_OPTIONS[constants.SCENE])
  311. #properties.option_embed_geometry = settings.get(
  312. # constants.EMBED_GEOMETRY,
  313. # constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
  314. properties.option_lights = settings.get(
  315. constants.LIGHTS,
  316. constants.EXPORT_OPTIONS[constants.LIGHTS])
  317. properties.option_cameras = settings.get(
  318. constants.CAMERAS,
  319. constants.EXPORT_OPTIONS[constants.CAMERAS])
  320. properties.option_hierarchy = settings.get(
  321. constants.HIERARCHY,
  322. constants.EXPORT_OPTIONS[constants.HIERARCHY])
  323. ## }
  324. ## Animation {
  325. properties.option_animation_morph = settings.get(
  326. constants.MORPH_TARGETS,
  327. constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
  328. properties.option_blend_shape = settings.get(
  329. constants.BLEND_SHAPES,
  330. constants.EXPORT_OPTIONS[constants.BLEND_SHAPES])
  331. properties.option_animation_skeletal = settings.get(
  332. constants.ANIMATION,
  333. constants.EXPORT_OPTIONS[constants.ANIMATION])
  334. properties.option_keyframes = settings.get(
  335. constants.KEYFRAMES,
  336. constants.EXPORT_OPTIONS[constants.KEYFRAMES])
  337. properties.option_bake_keyframes = settings.get(
  338. constants.BAKE_KEYFRAMES,
  339. constants.EXPORT_OPTIONS[constants.BAKE_KEYFRAMES])
  340. properties.option_frame_step = settings.get(
  341. constants.FRAME_STEP,
  342. constants.EXPORT_OPTIONS[constants.FRAME_STEP])
  343. properties.option_frame_index_as_time = settings.get(
  344. constants.FRAME_INDEX_AS_TIME,
  345. constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
  346. ## }
  347. def set_settings(properties):
  348. """Set the export settings to the correct keys.
  349. :param properties:
  350. :returns: settings
  351. :rtype: dict
  352. """
  353. settings = {
  354. constants.VERTICES: properties.option_vertices,
  355. constants.FACES: properties.option_faces,
  356. constants.NORMALS: properties.option_normals,
  357. constants.SKINNING: properties.option_skinning,
  358. constants.BONES: properties.option_bones,
  359. constants.EXTRA_VGROUPS: properties.option_extra_vgroups,
  360. constants.APPLY_MODIFIERS: properties.option_apply_modifiers,
  361. constants.GEOMETRY_TYPE: properties.option_geometry_type,
  362. constants.INDEX_TYPE: properties.option_index_type,
  363. constants.MATERIALS: properties.option_materials,
  364. constants.UVS: properties.option_uv_coords,
  365. constants.FACE_MATERIALS: properties.option_face_materials,
  366. constants.MAPS: properties.option_maps,
  367. constants.COLORS: properties.option_colors,
  368. constants.MIX_COLORS: properties.option_mix_colors,
  369. constants.SCALE: properties.option_scale,
  370. constants.ENABLE_PRECISION: properties.option_round_off,
  371. constants.PRECISION: properties.option_round_value,
  372. constants.CUSTOM_PROPERTIES: properties.option_custom_properties,
  373. constants.LOGGING: properties.option_logging,
  374. constants.COMPRESSION: properties.option_compression,
  375. constants.INDENT: properties.option_indent,
  376. constants.EXPORT_TEXTURES: properties.option_export_textures,
  377. constants.EMBED_TEXTURES: properties.option_embed_textures,
  378. constants.TEXTURE_FOLDER: properties.option_texture_folder,
  379. constants.SCENE: properties.option_export_scene,
  380. #constants.EMBED_GEOMETRY: properties.option_embed_geometry,
  381. constants.EMBED_ANIMATION: properties.option_embed_animation,
  382. constants.LIGHTS: properties.option_lights,
  383. constants.CAMERAS: properties.option_cameras,
  384. constants.HIERARCHY: properties.option_hierarchy,
  385. constants.MORPH_TARGETS: properties.option_animation_morph,
  386. constants.BLEND_SHAPES: properties.option_blend_shape,
  387. constants.ANIMATION: properties.option_animation_skeletal,
  388. constants.KEYFRAMES: properties.option_keyframes,
  389. constants.BAKE_KEYFRAMES: properties.option_bake_keyframes,
  390. constants.FRAME_STEP: properties.option_frame_step,
  391. constants.FRAME_INDEX_AS_TIME: properties.option_frame_index_as_time,
  392. constants.INFLUENCES_PER_VERTEX: properties.option_influences
  393. }
  394. return settings
  395. def compression_types():
  396. """Supported compression formats
  397. :rtype: tuple
  398. """
  399. types = [(constants.NONE, constants.NONE, constants.NONE)]
  400. try:
  401. import msgpack
  402. types.append((constants.MSGPACK, constants.MSGPACK,
  403. constants.MSGPACK))
  404. except ImportError:
  405. pass
  406. return types
  407. def animation_options():
  408. """The supported skeletal animation types
  409. :returns: list of tuples
  410. """
  411. anim = [
  412. (constants.OFF, constants.OFF.title(), constants.OFF),
  413. (constants.POSE, constants.POSE.title(), constants.POSE),
  414. (constants.REST, constants.REST.title(), constants.REST)
  415. ]
  416. return anim
  417. def resolve_conflicts(self, context):
  418. if(not self.option_export_textures):
  419. self.option_embed_textures = False;
  420. class ExportThree(bpy.types.Operator, ExportHelper):
  421. """Class that handles the export properties"""
  422. bl_idname = 'export.three'
  423. bl_label = 'Export THREE'
  424. bl_options = {'PRESET'}
  425. filename_ext = constants.EXTENSION
  426. option_vertices = BoolProperty(
  427. name="Vertices",
  428. description="Export vertices",
  429. default=constants.EXPORT_OPTIONS[constants.VERTICES])
  430. option_faces = BoolProperty(
  431. name="Faces",
  432. description="Export faces (Geometry only)",
  433. default=constants.EXPORT_OPTIONS[constants.FACES])
  434. option_normals = BoolProperty(
  435. name="Normals",
  436. description="Export normals",
  437. default=constants.EXPORT_OPTIONS[constants.NORMALS])
  438. option_colors = BoolProperty(
  439. name="Vertex Colors",
  440. description="Export vertex colors",
  441. default=constants.EXPORT_OPTIONS[constants.COLORS])
  442. option_mix_colors = BoolProperty(
  443. name="Mix Colors",
  444. description="Mix material and vertex colors",
  445. default=constants.EXPORT_OPTIONS[constants.MIX_COLORS])
  446. option_uv_coords = BoolProperty(
  447. name="UVs",
  448. description="Export texture coordinates",
  449. default=constants.EXPORT_OPTIONS[constants.UVS])
  450. option_materials = BoolProperty(
  451. name="Materials",
  452. description="Export materials",
  453. default=constants.EXPORT_OPTIONS[constants.MATERIALS])
  454. option_face_materials = BoolProperty(
  455. name="Face Materials",
  456. description="Face mapping materials (Geometry only)",
  457. default=constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
  458. option_maps = BoolProperty(
  459. name="Textures",
  460. description="Include texture maps",
  461. default=constants.EXPORT_OPTIONS[constants.MAPS])
  462. option_skinning = BoolProperty(
  463. name="Skinning",
  464. description="Export skin data",
  465. default=constants.EXPORT_OPTIONS[constants.SKINNING])
  466. option_bones = BoolProperty(
  467. name="Bones",
  468. description="Export bones",
  469. default=constants.EXPORT_OPTIONS[constants.BONES])
  470. option_extra_vgroups = StringProperty(
  471. name="Extra Vertex Groups",
  472. description="Non-skinning vertex groups to export (comma-separated, w/ star wildcard, BufferGeometry only).",
  473. default=constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
  474. option_apply_modifiers = BoolProperty(
  475. name="Apply Modifiers",
  476. description="Apply Modifiers to mesh objects",
  477. default=constants.EXPORT_OPTIONS[constants.APPLY_MODIFIERS]
  478. )
  479. index_buffer_types = [
  480. (constants.NONE,) * 3,
  481. (constants.UINT_16,) * 3,
  482. (constants.UINT_32,) * 3]
  483. option_index_type = EnumProperty(
  484. name="Index Buffer",
  485. description="Index buffer type that will be used for BufferGeometry objects.",
  486. items=index_buffer_types,
  487. default=constants.EXPORT_OPTIONS[constants.INDEX_TYPE])
  488. option_scale = FloatProperty(
  489. name="Scale",
  490. description="Scale vertices",
  491. min=0.01,
  492. max=1000.0,
  493. soft_min=0.01,
  494. soft_max=1000.0,
  495. default=constants.EXPORT_OPTIONS[constants.SCALE])
  496. option_round_off = BoolProperty(
  497. name="Enable Precision",
  498. description="Round off floating point values",
  499. default=constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
  500. option_round_value = IntProperty(
  501. name="",
  502. min=0,
  503. max=16,
  504. description="Floating point precision",
  505. default=constants.EXPORT_OPTIONS[constants.PRECISION])
  506. option_custom_properties = BoolProperty(
  507. name="Custom Properties",
  508. description="Export custom properties as userData",
  509. default=False)
  510. logging_types = [
  511. (constants.DISABLED, constants.DISABLED, constants.DISABLED),
  512. (constants.DEBUG, constants.DEBUG, constants.DEBUG),
  513. (constants.INFO, constants.INFO, constants.INFO),
  514. (constants.WARNING, constants.WARNING, constants.WARNING),
  515. (constants.ERROR, constants.ERROR, constants.ERROR),
  516. (constants.CRITICAL, constants.CRITICAL, constants.CRITICAL)]
  517. option_logging = EnumProperty(
  518. name="",
  519. description="Logging verbosity level",
  520. items=logging_types,
  521. default=constants.DISABLED)
  522. option_geometry_type = EnumProperty(
  523. name="Type",
  524. description="Geometry type",
  525. items=_geometry_types()[1:],
  526. default=constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
  527. option_export_scene = BoolProperty(
  528. name="Scene",
  529. description="Export scene",
  530. default=constants.EXPORT_OPTIONS[constants.SCENE])
  531. #@TODO: removing this option since the ObjectLoader doesn't have
  532. # support for handling external geometry data
  533. #option_embed_geometry = BoolProperty(
  534. # name="Embed geometry",
  535. # description="Embed geometry",
  536. # default=constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
  537. option_embed_animation = BoolProperty(
  538. name="Embed animation",
  539. description="Embed animation data with the geometry data",
  540. default=constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
  541. option_export_textures = BoolProperty(
  542. name="Export textures",
  543. description="Export textures",
  544. default=constants.EXPORT_OPTIONS[constants.EXPORT_TEXTURES],
  545. update=resolve_conflicts)
  546. option_embed_textures = BoolProperty(
  547. name="Embed textures",
  548. description="Embed base64 textures in .json",
  549. default=constants.EXPORT_OPTIONS[constants.EMBED_TEXTURES])
  550. option_texture_folder = StringProperty(
  551. name="Texture folder",
  552. description="add this folder to textures path",
  553. default=constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER])
  554. option_lights = BoolProperty(
  555. name="Lights",
  556. description="Export default scene lights",
  557. default=False)
  558. option_cameras = BoolProperty(
  559. name="Cameras",
  560. description="Export default scene cameras",
  561. default=False)
  562. option_hierarchy = BoolProperty(
  563. name="Hierarchy",
  564. description="Export object hierarchy",
  565. default=False)
  566. option_animation_morph = BoolProperty(
  567. name="Morph animation",
  568. description="Export animation (morphs)",
  569. default=constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
  570. option_blend_shape = BoolProperty(
  571. name="Blend Shape animation",
  572. description="Export Blend Shapes",
  573. default=constants.EXPORT_OPTIONS[constants.BLEND_SHAPES])
  574. option_animation_skeletal = EnumProperty(
  575. name="",
  576. description="Export animation (skeletal)",
  577. items=animation_options(),
  578. default=constants.OFF)
  579. option_keyframes = BoolProperty(
  580. name="Keyframe animation",
  581. description="Export animation (keyframes)",
  582. default=constants.EXPORT_OPTIONS[constants.KEYFRAMES])
  583. option_bake_keyframes = BoolProperty(
  584. name="Bake keyframe animation",
  585. description="Bake keyframe animation each frame step",
  586. default=constants.EXPORT_OPTIONS[constants.BAKE_KEYFRAMES])
  587. option_frame_index_as_time = BoolProperty(
  588. name="Frame index as time",
  589. description="Use (original) frame index as frame time",
  590. default=constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
  591. option_frame_step = IntProperty(
  592. name="Frame step",
  593. description="Animation frame step",
  594. min=1,
  595. max=1000,
  596. soft_min=1,
  597. soft_max=1000,
  598. default=1)
  599. option_indent = BoolProperty(
  600. name="Indent JSON",
  601. description="Disable this to reduce the file size",
  602. default=constants.EXPORT_OPTIONS[constants.INDENT])
  603. option_compression = EnumProperty(
  604. name="",
  605. description="Compression options",
  606. items=compression_types(),
  607. default=constants.NONE)
  608. option_influences = IntProperty(
  609. name="Influences",
  610. description="Maximum number of bone influences",
  611. min=1,
  612. max=4,
  613. default=2)
  614. def invoke(self, context, event):
  615. settings = context.scene.get(constants.EXPORT_SETTINGS_KEY)
  616. if settings:
  617. try:
  618. restore_export_settings(self.properties, settings)
  619. except AttributeError as e:
  620. logging.error("Loading export settings failed:")
  621. logging.exception(e)
  622. logging.debug("Removed corrupted settings")
  623. del context.scene[constants.EXPORT_SETTINGS_KEY]
  624. return ExportHelper.invoke(self, context, event)
  625. @classmethod
  626. def poll(cls, context):
  627. """
  628. :param context:
  629. """
  630. return context.active_object is not None
  631. def execute(self, context):
  632. """
  633. :param context:
  634. """
  635. if not self.properties.filepath:
  636. raise Exception("filename not set")
  637. settings = set_settings(self.properties)
  638. settings['addon_version'] = bl_info['version']
  639. filepath = self.filepath
  640. if settings[constants.COMPRESSION] == constants.MSGPACK:
  641. filepath = "%s%s" % (filepath[:-4], constants.PACK)
  642. from io_three import exporter
  643. if settings[constants.SCENE]:
  644. exporter.export_scene(filepath, settings)
  645. else:
  646. exporter.export_geometry(filepath, settings)
  647. return {'FINISHED'}
  648. def draw(self, context):
  649. """
  650. :param context:
  651. """
  652. using_geometry = self.option_geometry_type == constants.GEOMETRY
  653. layout = self.layout
  654. ## Scene {
  655. box = layout.box()
  656. column = box.column(True)
  657. row = column.row(True)
  658. row.alignment = 'CENTER'
  659. row.label(text="SCENE", icon="SCENE_DATA")
  660. row = box.row()
  661. row.prop(self.properties, 'option_export_scene')
  662. row.prop(self.properties, 'option_materials')
  663. #row = box.row()
  664. #row.prop(self.properties, 'option_embed_geometry')
  665. row = box.row()
  666. row.prop(self.properties, 'option_lights')
  667. row.prop(self.properties, 'option_cameras')
  668. row = box.row()
  669. row.prop(self.properties, 'option_hierarchy')
  670. ## }
  671. layout.separator()
  672. ## Geometry {
  673. box = layout.box()
  674. column = box.column(True)
  675. row = column.row(True)
  676. row.alignment = 'CENTER'
  677. row.label(text="GEOMETRY", icon="MESH_DATA")
  678. row = box.row()
  679. row.prop(self.properties, 'option_geometry_type')
  680. row = box.row()
  681. row.prop(self.properties, 'option_index_type')
  682. row = box.row()
  683. row.prop(self.properties, 'option_vertices')
  684. col = row.column()
  685. col.prop(self.properties, 'option_faces')
  686. col.enabled = using_geometry
  687. row = box.row()
  688. row.prop(self.properties, 'option_normals')
  689. row.prop(self.properties, 'option_uv_coords')
  690. row = box.row()
  691. row.prop(self.properties, 'option_apply_modifiers')
  692. row = box.row()
  693. row.prop(self.properties, 'option_extra_vgroups')
  694. row.enabled = not using_geometry
  695. ## }
  696. layout.separator()
  697. ## Materials {
  698. box = layout.box()
  699. column = box.column(True)
  700. row = column.row(True)
  701. row.alignment = 'CENTER'
  702. row.label(text="MATERIAL", icon="MATERIAL_DATA")
  703. row = box.row()
  704. row.prop(self.properties, 'option_colors')
  705. row.prop(self.properties, 'option_mix_colors')
  706. row = box.row()
  707. row.prop(self.properties, 'option_face_materials')
  708. row.enabled = using_geometry
  709. ## }
  710. layout.separator()
  711. ## Textures {
  712. box = layout.box()
  713. column = box.column(True)
  714. row = column.row(True)
  715. row.alignment = 'CENTER'
  716. row.label(text="TEXTURE", icon="TEXTURE_DATA")
  717. row = box.row()
  718. row.prop(self.properties, 'option_maps')
  719. row.prop(self.properties, 'option_export_textures')
  720. row = box.row()
  721. row.prop(self.properties, 'option_embed_textures')
  722. row.enabled = self.properties.option_export_textures
  723. row = box.row()
  724. row.prop(self.properties, 'option_texture_folder')
  725. ## }
  726. layout.separator()
  727. ## Armature {
  728. box = layout.box()
  729. column = box.column(True)
  730. row = column.row(True)
  731. row.alignment = 'CENTER'
  732. row.label(text="ARMATURE", icon="ARMATURE_DATA")
  733. row = box.row()
  734. row.prop(self.properties, 'option_bones')
  735. row.prop(self.properties, 'option_skinning')
  736. ## }
  737. layout.separator()
  738. ## Animation {
  739. box = layout.box()
  740. column = box.column(True)
  741. row = column.row(True)
  742. row.alignment = 'CENTER'
  743. row.label(text="ANIMATION", icon="POSE_DATA")
  744. row = box.row()
  745. row.prop(self.properties, 'option_animation_morph')
  746. row.prop(self.properties, 'option_blend_shape')
  747. row = box.row()
  748. row.label(text="Skeletal animations:")
  749. row.prop(self.properties, 'option_animation_skeletal')
  750. row = box.row()
  751. row.prop(self.properties, 'option_keyframes')
  752. row = box.row()
  753. row.prop(self.properties, 'option_bake_keyframes')
  754. row = box.row()
  755. row.prop(self.properties, 'option_influences')
  756. row = box.row()
  757. row.prop(self.properties, 'option_frame_step')
  758. row = box.row()
  759. row.prop(self.properties, 'option_frame_index_as_time')
  760. row = box.row()
  761. row.prop(self.properties, 'option_embed_animation')
  762. ## }
  763. layout.separator()
  764. ## Settings {
  765. box = layout.box()
  766. column = box.column(True)
  767. row = column.row(True)
  768. row.alignment = 'CENTER'
  769. row.label(text="SETTINGS", icon="SETTINGS")
  770. row = box.row()
  771. row.prop(self.properties, 'option_scale')
  772. row = box.row()
  773. row.prop(self.properties, 'option_round_off')
  774. row.prop(self.properties, 'option_round_value')
  775. row = box.row()
  776. row.prop(self.properties, 'option_custom_properties')
  777. row = box.row()
  778. row.prop(self.properties, 'option_indent')
  779. row = box.row()
  780. row.label(text="Logging verbosity:")
  781. row.prop(self.properties, 'option_logging')
  782. row = box.row()
  783. row.label(text="File compression format:")
  784. row.prop(self.properties, 'option_compression')
  785. ## }
  786. ## Operators {
  787. has_settings = context.scene.get(constants.EXPORT_SETTINGS_KEY, False)
  788. row = layout.row()
  789. row.operator(
  790. ThreeExportSettings.bl_idname,
  791. ThreeExportSettings.bl_label,
  792. icon="%s" % "PINNED" if has_settings else "UNPINNED")
  793. ## }
  794. def menu_func_export(self, context):
  795. """
  796. :param self:
  797. :param context:
  798. """
  799. default_path = bpy.data.filepath.replace('.blend', constants.EXTENSION)
  800. text = "Three.js (%s)" % constants.EXTENSION
  801. operator = self.layout.operator(ExportThree.bl_idname, text=text)
  802. operator.filepath = default_path
  803. def register():
  804. """Registers the addon (Blender boilerplate)"""
  805. bpy.utils.register_module(__name__)
  806. bpy.types.INFO_MT_file_export.append(menu_func_export)
  807. def unregister():
  808. """Unregisters the addon (Blender boilerplate)"""
  809. bpy.utils.unregister_module(__name__)
  810. bpy.types.INFO_MT_file_export.remove(menu_func_export)
  811. if __name__ == '__main__':
  812. register()