diff --git a/io_scene_3ds/__init__.py b/io_scene_3ds/__init__.py index eeddb37cd..c0c13aa1b 100644 --- a/io_scene_3ds/__init__.py +++ b/io_scene_3ds/__init__.py @@ -55,7 +55,7 @@ class Import3DS(bpy.types.Operator, ImportHelper): soft_min=0.0, soft_max=1000.0, default=10.0, ) - convert_unit: BoolProperty( + use_scene_unit: BoolProperty( name="Scene Units", description="Converts to scene unit length settings", default=False, @@ -72,7 +72,7 @@ class Import3DS(bpy.types.Operator, ImportHelper): ('MESH', "Mesh".rjust(11), "", 'MESH_DATA', 0x2), ('LIGHT', "Light".rjust(12), "", 'LIGHT_DATA', 0x4), ('CAMERA', "Camera".rjust(11), "", 'CAMERA_DATA', 0x8), - ('EMPTY', "Empty".rjust(11), "", 'EMPTY_DATA', 0x10), + ('EMPTY', "Empty".rjust(11), "", 'EMPTY_AXIS', 0x10), ), description="Object types to import", default={'WORLD', 'MESH', 'LIGHT', 'CAMERA', 'EMPTY'}, @@ -83,7 +83,7 @@ class Import3DS(bpy.types.Operator, ImportHelper): "importing incorrectly", default=True, ) - read_keyframe: BoolProperty( + use_keyframes: BoolProperty( name="Animation", description="Read the keyframe data", default=True, @@ -93,6 +93,11 @@ class Import3DS(bpy.types.Operator, ImportHelper): description="Transform to matrix world", default=False, ) + use_cursor: BoolProperty( + name="Cursor Origin", + description="Read the 3D cursor location", + default=False, + ) def execute(self, context): from . import import_3ds @@ -139,8 +144,11 @@ class MAX3DS_PT_import_include(bpy.types.Panel): layrow.label(text="", icon='OUTLINER_OB_IMAGE' if operator.use_image_search else 'IMAGE_DATA') layout.column().prop(operator, "object_filter") layrow = layout.row(align=True) - layrow.prop(operator, "read_keyframe") - layrow.label(text="", icon='ANIM' if operator.read_keyframe else 'DECORATE_DRIVER') + layrow.prop(operator, "use_keyframes") + layrow.label(text="", icon='ANIM' if operator.use_keyframes else 'DECORATE_DRIVER') + layrow = layout.row(align=True) + layrow.prop(operator, "use_cursor") + layrow.label(text="", icon='PIVOT_CURSOR' if operator.use_cursor else 'CURSOR') class MAX3DS_PT_import_transform(bpy.types.Panel): @@ -166,8 +174,8 @@ class MAX3DS_PT_import_transform(bpy.types.Panel): layout.prop(operator, "constrain_size") layrow = layout.row(align=True) - layrow.prop(operator, "convert_unit") - layrow.label(text="", icon='EMPTY_ARROWS' if operator.convert_unit else 'EMPTY_DATA') + layrow.prop(operator, "use_scene_unit") + layrow.label(text="", icon='EMPTY_ARROWS' if operator.use_scene_unit else 'EMPTY_DATA') layrow = layout.row(align=True) layrow.prop(operator, "use_apply_transform") layrow.label(text="", icon='MESH_CUBE' if operator.use_apply_transform else 'MOD_SOLIDIFY') @@ -198,7 +206,7 @@ class Export3DS(bpy.types.Operator, ExportHelper): soft_min=0.0, soft_max=100000.0, default=1.0, ) - apply_unit: BoolProperty( + use_scene_unit: BoolProperty( name="Scene Units", description="Take the scene unit length settings into account", default=False, @@ -214,7 +222,7 @@ class Export3DS(bpy.types.Operator, ExportHelper): ('MESH', "Mesh".rjust(11), "", 'MESH_DATA', 0x2), ('LIGHT', "Light".rjust(12), "", 'LIGHT_DATA',0x4), ('CAMERA', "Camera".rjust(11), "", 'CAMERA_DATA',0x8), - ('EMPTY', "Empty".rjust(11), "", 'EMPTY_DATA',0x10), + ('EMPTY', "Empty".rjust(11), "", 'EMPTY_AXIS',0x10), ), description="Object types to export", default={'WORLD', 'MESH', 'LIGHT', 'CAMERA', 'EMPTY'}, @@ -224,11 +232,16 @@ class Export3DS(bpy.types.Operator, ExportHelper): description="Export hierarchy chunks", default=False, ) - write_keyframe: BoolProperty( + use_keyframes: BoolProperty( name="Animation", description="Write the keyframe data", default=False, ) + use_cursor: BoolProperty( + name="Cursor Origin", + description="Save the 3D cursor location", + default=False, + ) def execute(self, context): from . import export_3ds @@ -278,9 +291,11 @@ class MAX3DS_PT_export_include(bpy.types.Panel): layrow.prop(operator, "use_hierarchy") layrow.label(text="", icon='OUTLINER' if operator.use_hierarchy else 'CON_CHILDOF') layrow = layout.row(align=True) - layrow.prop(operator, "write_keyframe") - layrow.label(text="", icon='ANIM' if operator.write_keyframe else 'DECORATE_DRIVER') - layout.use_property_split = True + layrow.prop(operator, "use_keyframes") + layrow.label(text="", icon='ANIM' if operator.use_keyframes else 'DECORATE_DRIVER') + layrow = layout.row(align=True) + layrow.prop(operator, "use_cursor") + layrow.label(text="", icon='PIVOT_CURSOR' if operator.use_cursor else 'CURSOR') class MAX3DS_PT_export_transform(bpy.types.Panel): @@ -306,8 +321,8 @@ class MAX3DS_PT_export_transform(bpy.types.Panel): layout.prop(operator, "scale_factor") layrow = layout.row(align=True) - layrow.prop(operator, "apply_unit") - layrow.label(text="", icon='EMPTY_ARROWS' if operator.apply_unit else 'EMPTY_DATA') + layrow.prop(operator, "use_scene_unit") + layrow.label(text="", icon='EMPTY_ARROWS' if operator.use_scene_unit else 'EMPTY_DATA') layout.prop(operator, "axis_forward") layout.prop(operator, "axis_up") diff --git a/io_scene_3ds/export_3ds.py b/io_scene_3ds/export_3ds.py index d4d53b834..0ffedc299 100644 --- a/io_scene_3ds/export_3ds.py +++ b/io_scene_3ds/export_3ds.py @@ -36,6 +36,7 @@ SOLIDBACKGND = 0x1200 # The background color (RGB) USE_SOLIDBGND = 0x1201 # The background color flag VGRADIENT = 0x1300 # The background gradient colors USE_VGRADIENT = 0x1301 # The background gradient flag +O_CONSTS = 0x1500 # The origin of the 3D cursor AMBIENTLIGHT = 0x2100 # The color of the ambient light LAYER_FOG = 0x2302 # The fog atmosphere settings USE_LAYER_FOG = 0x2303 # The fog atmosphere flag @@ -1497,8 +1498,8 @@ def make_ambient_node(world): # EXPORT # ########## -def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use_selection=False, - object_filter=None, use_hierarchy=False, write_keyframe=False, global_matrix=None): +def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False, use_selection=False, + object_filter=None, use_hierarchy=False, use_keyframes=False, global_matrix=None, use_cursor=False): """Save the Blender scene to a 3ds file.""" # Time the export @@ -1511,7 +1512,7 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use world = scene.world unit_measure = 1.0 - if apply_unit: + if use_scene_unit: unit_length = scene.unit_settings.length_unit if unit_length == 'KILOMETERS': unit_measure = 0.001 @@ -1549,21 +1550,29 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use mscale.add_variable("scale", _3ds_float(1.0)) object_info.add_subchunk(mscale) + # Add 3D cursor location + if use_cursor: + cursor_chunk = _3ds_chunk(O_CONSTS) + cursor_chunk.add_variable("cursor", _3ds_point_3d(scene.cursor.location)) + object_info.add_subchunk(cursor_chunk) + # Init main keyframe data chunk - if write_keyframe: + if use_keyframes: revision = 0x0005 stop = scene.frame_end start = scene.frame_start curtime = scene.frame_current kfdata = make_kfdata(revision, start, stop, curtime) - # Add AMBIENT, BACKGROUND and BITMAP + # Add AMBIENT color if world is not None and 'WORLD' in object_filter: ambient_chunk = _3ds_chunk(AMBIENTLIGHT) ambient_light = _3ds_chunk(RGB) ambient_light.add_variable("ambient", _3ds_float_color(world.color)) ambient_chunk.add_subchunk(ambient_light) object_info.add_subchunk(ambient_chunk) + + # Add BACKGROUND and BITMAP if world.use_nodes: ntree = world.node_tree.links background_color_chunk = _3ds_chunk(RGB) @@ -1604,7 +1613,7 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use object_info.add_subchunk(fog_chunk) if layer.use_pass_mist: object_info.add_subchunk(use_fog_flag) - if write_keyframe and world.animation_data: + if use_keyframes and world.animation_data: kfdata.add_subchunk(make_ambient_node(world)) # Make a list of all materials used in the selected meshes (use dictionary, each material is added once) @@ -1746,13 +1755,13 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use operator.report({'WARNING'}, "Object %r can't be written into a 3DS file") # Export object node - if write_keyframe: + if use_keyframes: kfdata.add_subchunk(make_object_node(ob, translation, rotation, scale, name_id)) i += i # Create chunks for all empties - only requires a object node - if write_keyframe: + if use_keyframes: for ob in empty_objects: kfdata.add_subchunk(make_object_node(ob, translation, rotation, scale, name_id)) @@ -1816,7 +1825,7 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use object_info.add_subchunk(object_chunk) # Export light and spotlight target node - if write_keyframe: + if use_keyframes: kfdata.add_subchunk(make_object_node(ob, translation, rotation, scale, name_id)) if ob.data.type == 'SPOT': kfdata.add_subchunk(make_target_node(ob, translation, rotation, scale, name_id)) @@ -1850,7 +1859,7 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use object_info.add_subchunk(object_chunk) # Export camera and target node - if write_keyframe: + if use_keyframes: kfdata.add_subchunk(make_object_node(ob, translation, rotation, scale, name_id)) kfdata.add_subchunk(make_target_node(ob, translation, rotation, scale, name_id)) @@ -1858,7 +1867,7 @@ def save(operator, context, filepath="", scale_factor=1.0, apply_unit=False, use primary.add_subchunk(object_info) # Add main keyframe data chunk to primary chunk - if write_keyframe: + if use_keyframes: primary.add_subchunk(kfdata) # The chunk hierarchy is completely built, now check the size diff --git a/io_scene_3ds/import_3ds.py b/io_scene_3ds/import_3ds.py index 12e606c48..4df55c7af 100644 --- a/io_scene_3ds/import_3ds.py +++ b/io_scene_3ds/import_3ds.py @@ -43,6 +43,7 @@ SOLIDBACKGND = 0x1200 # The background color (RGB) USE_SOLIDBGND = 0x1201 # The background color flag VGRADIENT = 0x1300 # The background gradient colors USE_VGRADIENT = 0x1301 # The background gradient flag +O_CONSTS = 0x1500 # The origin of the 3D cursor AMBIENTLIGHT = 0x2100 # The color of the ambient light LAYER_FOG = 0x2302 # The fog atmosphere settings USE_LAYER_FOG = 0x2303 # The fog atmosphere flag @@ -333,8 +334,8 @@ def add_texture_to_material(image, contextWrapper, pct, extend, alpha, scale, of childs_list = [] parent_list = [] -def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAIN, - FILTER, IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE): +def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAIN, FILTER, + IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE, CURSOR): contextObName = None contextWorld = None @@ -679,6 +680,10 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI if version > 3: print("\tNon-Fatal Error: Version greater than 3, may not load correctly: ", version) + # If cursor location + elif CURSOR and new_chunk.ID == O_CONSTS: + context.scene.cursor.location = read_float_array(new_chunk) + # If ambient light chunk elif CreateWorld and new_chunk.ID == AMBIENTLIGHT: path, filename = os.path.split(file.name) @@ -768,8 +773,8 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI # is it an object info chunk? elif new_chunk.ID == OBJECTINFO: - process_next_chunk(context, file, new_chunk, imported_objects, CONSTRAIN, - FILTER, IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE) + process_next_chunk(context, file, new_chunk, imported_objects, CONSTRAIN, FILTER, + IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE, CURSOR) # keep track of how much we read in the main chunk new_chunk.bytes_read += temp_chunk.bytes_read @@ -1416,7 +1421,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI ########## def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True, FILTER=None, - WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True, CONVERSE=None): + WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True, CONVERSE=None, CURSOR=False): print("importing 3DS: %r..." % (filepath), end="") @@ -1458,8 +1463,8 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True, MEASURE = 0.000001 imported_objects = [] # Fill this list with objects - process_next_chunk(context, file, current_chunk, imported_objects, CONSTRAIN, - FILTER, IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE) + process_next_chunk(context, file, current_chunk, imported_objects, CONSTRAIN, FILTER, + IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE, CURSOR) # fixme, make unglobal object_dictionary.clear() @@ -1553,12 +1558,12 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True, file.close() -def load(operator, context, filepath="", constrain_size=0.0, convert_unit=False, +def load(operator, context, filepath="", constrain_size=0.0, use_scene_unit=False, use_image_search=True, object_filter=None, use_world_matrix=False, - read_keyframe=True, use_apply_transform=True, global_matrix=None,): + use_keyframes=True, use_apply_transform=True, global_matrix=None, use_cursor=False): - load_3ds(filepath, context, CONSTRAIN=constrain_size, UNITS=convert_unit, + load_3ds(filepath, context, CONSTRAIN=constrain_size, UNITS=use_scene_unit, IMAGE_SEARCH=use_image_search, FILTER=object_filter, WORLD_MATRIX=use_world_matrix, - KEYFRAME=read_keyframe, APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix,) + KEYFRAME=use_keyframes, APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix, CURSOR=use_cursor,) return {'FINISHED'}