diff --git a/io_scene_3ds/export_3ds.py b/io_scene_3ds/export_3ds.py index 2b2baeb92..608c76171 100644 --- a/io_scene_3ds/export_3ds.py +++ b/io_scene_3ds/export_3ds.py @@ -121,6 +121,7 @@ KFDATA_KFCURTIME = 0xB009 # Frame current KFDATA_KFHDR = 0xB00A # Keyframe header # >------ sub defines of OBJECT_NODE_TAG +PARENT_NAME = 0x80F0 # Object parent name tree OBJECT_NODE_ID = 0xB030 # Object hierachy ID OBJECT_NODE_HDR = 0xB010 # Hierachy tree header OBJECT_INSTANCE_NAME = 0xB011 # Object instance name @@ -149,7 +150,7 @@ def sane_name(name): if name_fixed is not None: return name_fixed - # strip non ascii chars + # Strip non ascii chars new_name_clean = new_name = name.encode("ASCII", "replace").decode("ASCII")[:12] i = 0 @@ -157,7 +158,7 @@ def sane_name(name): new_name = new_name_clean + '.%.3d' % i i += 1 - # note, appending the 'str' version + # Note, appending the 'str' version name_unique.append(new_name) name_mapping[name] = new_name = new_name.encode("ASCII", "replace") return new_name @@ -166,7 +167,7 @@ def sane_name(name): def uv_key(uv): return round(uv[0], 6), round(uv[1], 6) -# size defines +# Size defines SZ_SHORT = 2 SZ_INT = 4 SZ_FLOAT = 4 @@ -238,7 +239,7 @@ class _3ds_string(object): file.write(struct.pack(binary_format, self.value)) def __str__(self): - return str(self.value) + return str((self.value).decode("ASCII")) class _3ds_point_3d(object): @@ -341,7 +342,7 @@ class _3ds_face(object): def get_size(self): return 4 * SZ_SHORT - # no need to validate every face vert, the oversized array will catch this problem + # No need to validate every face vert, the oversized array will catch this problem def write(self, file): # The last short is used for face flags file.write(struct.pack('<4H', self.vindex[0], self.vindex[1], self.vindex[2], self.flag)) @@ -353,13 +354,14 @@ class _3ds_face(object): class _3ds_array(object): """Class representing an array of variables for a 3ds file. Consists of a _3ds_ushort to indicate the number of items, followed by the items themselves.""" + __slots__ = "values", "size" def __init__(self): self.values = [] self.size = SZ_SHORT - # add an item + # Add an item def add(self, item): self.values.append(item) self.size += item.get_size() @@ -383,7 +385,6 @@ class _3ds_array(object): class _3ds_named_variable(object): """Convenience class for named variables.""" - __slots__ = "value", "name" def __init__(self, name, val=None): @@ -408,11 +409,11 @@ class _3ds_named_variable(object): self.value) -# the chunk class +# The chunk class class _3ds_chunk(object): """Class representing a chunk in a 3ds file. - Chunks contain zero or more variables, followed by zero or more subchunks. - """ + Chunks contain zero or more variables, followed by zero or more subchunks.""" + __slots__ = "ID", "size", "variables", "subchunks" def __init__(self, chunk_id=0): @@ -460,7 +461,7 @@ class _3ds_chunk(object): """Write the chunk to a file. Uses the write function of the variables and the subchunks to do the actual work.""" - # write header + # Write header self.ID.write(file) self.size.write(file) for variable in self.variables: @@ -481,9 +482,9 @@ class _3ds_chunk(object): subchunk.dump(indent + 1) -########## -# EXPORT # -########## +############# +# MATERIALS # +############# def get_material_image(material): """ Get images from paint slots.""" @@ -514,7 +515,7 @@ def make_material_subchunk(chunk_id, color): col1 = _3ds_chunk(RGB1) col1.add_variable("color1", _3ds_rgb_color(color)) mat_sub.add_subchunk(col1) - # optional: + # Optional # col2 = _3ds_chunk(RGBI) # col2.add_variable("color2", _3ds_rgb_color(color)) # mat_sub.add_subchunk(col2) @@ -527,7 +528,7 @@ def make_percent_subchunk(chunk_id, percent): pcti = _3ds_chunk(PCT) pcti.add_variable("percent", _3ds_ushort(int(round(percent * 100, 0)))) pct_sub.add_subchunk(pcti) - # optional: + # Optional # pctf = _3ds_chunk(PCTF) # pctf.add_variable("pctfloat", _3ds_float(round(percent, 6))) # pct_sub.add_subchunk(pctf) @@ -579,7 +580,7 @@ def make_material_texture_chunk(chunk_id, texslots, pct): 0x40 activates alpha source, 0x80 activates tinting, 0x100 ignores alpha, 0x200 activates RGB tint. Bits 0x80, 0x100, and 0x200 are only used with TEXMAP, TEX2MAP, and SPECMAP chunks. 0x40, when used with a TEXMAP, TEX2MAP, or SPECMAP chunk must be accompanied with a tint bit, - either 0x100 or 0x200, tintcolor will be processed if tintflags are present""" + either 0x100 or 0x200, tintcolor will be processed if a tintflag is present""" mapflags = 0 if texslot.extension == 'EXTEND': @@ -628,7 +629,7 @@ def make_material_texture_chunk(chunk_id, texslots, pct): rgb.add_variable("mapcolor", _3ds_rgb_color(spec if texslot.socket_dst.identifier == 'Specular' else base)) mat_sub.add_subchunk(rgb) - # store all textures for this mapto in order. This at least is what the + # Store all textures for this mapto in order. This at least is what the # 3DS exporter did so far, afaik most readers will just skip over 2nd textures for slot in texslots: if slot.image is not None: @@ -730,7 +731,7 @@ def make_material_chunk(material, image): if matmap: material_chunk.add_subchunk(matmap) - # make sure no textures are lost. Everything that doesn't fit + # Make sure no textures are lost. Everything that doesn't fit # into a channel is exported as secondary texture diffuse = [] @@ -757,7 +758,7 @@ def make_material_chunk(material, image): material_chunk.add_subchunk(make_percent_subchunk(MATTRANS, 1 - material.diffuse_color[3])) material_chunk.add_subchunk(shading) - slots = [get_material_image(material)] # can be None + slots = [get_material_image(material)] # Can be None if image: material_chunk.add_subchunk(make_texture_chunk(MAT_DIFFUSEMAP, slots)) @@ -765,6 +766,10 @@ def make_material_chunk(material, image): return material_chunk +############# +# MESH DATA # +############# + class tri_wrapper(object): """Class representing a triangle. Used when converting faces to triangles""" @@ -776,7 +781,7 @@ class tri_wrapper(object): self.ma = ma self.image = image self.faceuvs = faceuvs - self.offset = [0, 0, 0] # offset indices + self.offset = [0, 0, 0] # Offset indices self.flag = flag self.group = group @@ -844,13 +849,13 @@ def remove_face_uv(verts, tri_list): need to be converted to vertex uv coordinates. That means that vertices need to be duplicated when there are multiple uv coordinates per vertex.""" - # initialize a list of UniqueLists, one per vertex + # Initialize a list of UniqueLists, one per vertex unique_uvs = [{} for i in range(len(verts))] - # for each face uv coordinate, add it to the UniqueList of the vertex + # For each face uv coordinate, add it to the UniqueList of the vertex for tri in tri_list: for i in range(3): - # store the index into the UniqueList for future reference: + # Store the index into the UniqueList for future reference # offset.append(uv_list[tri.vertex_index[i]].add(_3ds_point_uv(tri.faceuvs[i]))) context_uv_vert = unique_uvs[tri.vertex_index[i]] @@ -862,7 +867,7 @@ def remove_face_uv(verts, tri_list): tri.offset[i] = offset_index__uv_3ds[0] - # At this point, each vertex has a UniqueList containing every uv coordinate associated with it only once + # At this point each vertex has a UniqueList containing every uv coord associated with it only once # Now we need to duplicate every vertex as many times as it has uv coordinates and make sure the # faces refer to the new face indices vert_index = 0 @@ -875,16 +880,15 @@ def remove_face_uv(verts, tri_list): pt = _3ds_point_3d(vert.co) # reuse, should be ok uvmap = [None] * len(unique_uvs[i]) for ii, uv_3ds in unique_uvs[i].values(): - # add a vertex duplicate to the vertex_array for every uv associated with this vertex + # Add a vertex duplicate to the vertex_array for every uv associated with this vertex vert_array.add(pt) - # add the uv coordinate to the uv array, this for loop does not give + # Add the uv coordinate to the uv array, this for loop does not give # uv's ordered by ii, so we create a new map and add the uv's later # uv_array.add(uv_3ds) uvmap[ii] = uv_3ds - # Add the uv's in the correct order + # Add uv's in the correct order and add coordinates to the uv array for uv_3ds in uvmap: - # add the uv coordinate to the uv array uv_array.add(uv_3ds) vert_index += len(unique_uvs[i]) @@ -1004,23 +1008,21 @@ def make_mesh_chunk(ob, mesh, matrix, materialDict, translation): vert_array = _3ds_array() for vert in mesh.vertices: vert_array.add(_3ds_point_3d(vert.co)) - # no UV at all + # No UV at all uv_array = None - # create the chunk + # Create the chunk mesh_chunk = _3ds_chunk(OBJECT_MESH) - # add vertex chunk + # Add vertex and faces chunk mesh_chunk.add_subchunk(make_vert_chunk(vert_array)) - - # add faces chunk mesh_chunk.add_subchunk(make_faces_chunk(tri_list, mesh, materialDict)) - # if available, add uv chunk + # If available, add uv chunk if uv_array: mesh_chunk.add_subchunk(make_uv_chunk(uv_array)) - # create transformation matrix chunk + # Create transformation matrix chunk matrix_chunk = _3ds_chunk(OBJECT_TRANS_MATRIX) obj_matrix = matrix.transposed().to_3x3() @@ -1170,9 +1172,14 @@ def make_kf_obj_node(obj, name_to_id): ''' +########## +# EXPORT # +########## + def save(operator, context, filepath="", - use_selection=True, + use_selection=False, + write_keyframe=False, global_matrix=None, ): @@ -1222,8 +1229,7 @@ def save(operator, kfdata = make_kfdata() ''' - # Make a list of all materials used in the selected meshes (use a dictionary, - # each material is added once) + # Make a list of all materials used in the selected meshes (use dictionary, each material is added once) materialDict = {} mesh_objects = [] @@ -1237,7 +1243,7 @@ def save(operator, camera_objects = [ob for ob in objects if ob.type == 'CAMERA'] for ob in objects: - # get derived objects + # Get derived objects derived_dict = bpy_extras.io_utils.create_derived_objects(depsgraph, [ob]) derived = derived_dict.get(ob) @@ -1260,7 +1266,7 @@ def save(operator, ma_ls = data.materials ma_ls_len = len(ma_ls) - # get material/image tuples + # Get material/image tuples if data.uv_layers: if not ma_ls: ma = ma_name = None @@ -1272,7 +1278,7 @@ def save(operator, ma_index = f.material_index = 0 ma = ma_ls[ma_index] ma_name = None if ma is None else ma.name - # else there already set to none + # Else there already set to none img = get_uv_image(ma) img_name = None if img is None else img.name @@ -1281,7 +1287,7 @@ def save(operator, else: for ma in ma_ls: - if ma: # material may be None so check its not + if ma: # Material may be None so check its not materialDict.setdefault((ma.name, None), (ma, None)) # Why 0 Why! @@ -1302,22 +1308,26 @@ def save(operator, for ob, data, matrix in mesh_objects: translation[ob.name] = ob.location + rotation[ob.name] = ob.rotation_euler.to_quaternion().inverted() + scale[ob.name] = ob.scale # name_to_id[ob.name]= len(name_to_id) for ob in empty_objects: translation[ob.name] = ob.location + rotation[ob.name] = ob.rotation_euler.to_quaternion().inverted() + scale[ob.name] = ob.scale # name_to_id[ob.name]= len(name_to_id) # Create object chunks for all meshes i = 0 for ob, mesh, matrix in mesh_objects: - # create a new object chunk + # Create a new object chunk object_chunk = _3ds_chunk(OBJECT) - # set the object name + # Set the object name object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) - # make a mesh chunk out of the mesh + # Make a mesh chunk out of the mesh object_chunk.add_subchunk(make_mesh_chunk(ob, mesh, matrix, materialDict, translation)) # Ensure the mesh has no over sized arrays, skip ones that do! @@ -1334,7 +1344,7 @@ def save(operator, i += i - # Create chunks for all empties + # Create chunks for all empties: ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX for ob in empty_objects: # Empties only require a kf object node: @@ -1397,7 +1407,7 @@ def save(operator, object_chunk.add_subchunk(camera_chunk) object_info.add_subchunk(object_chunk) - # Add main object info chunk to primary chunk + # Add main object info chunk to primary chunk: primary.add_subchunk(object_info) ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 2dab4d9f9..0efce119d 100755 --- a/io_scene_gltf2/__init__.py +++ b/io_scene_gltf2/__init__.py @@ -4,7 +4,7 @@ bl_info = { 'name': 'glTF 2.0 format', 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors', - "version": (3, 6, 18), + "version": (4, 0, 0), 'blender': (3, 5, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/node_wrangler/operators.py b/node_wrangler/operators.py index 51f9d14a1..78d2b78cb 100644 --- a/node_wrangler/operators.py +++ b/node_wrangler/operators.py @@ -1349,7 +1349,6 @@ class NWMergeNodes(Operator, NWBase): if tree_type == 'COMPOSITING': first = 1 second = 2 - add.width_hidden = 100.0 elif nodes_list == selected_math: add_type = node_type + 'Math' add = nodes.new(add_type) @@ -1359,7 +1358,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 0 second = 1 - add.width_hidden = 100.0 elif nodes_list == selected_shader: if mode == 'MIX': add_type = node_type + 'MixShader' @@ -1369,7 +1367,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 1 second = 2 - add.width_hidden = 100.0 elif mode == 'ADD': add_type = node_type + 'AddShader' add = nodes.new(add_type) @@ -1378,7 +1375,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 0 second = 1 - add.width_hidden = 100.0 elif nodes_list == selected_geometry: if mode in ('JOIN', 'MIX'): add_type = node_type + 'JoinGeometry' @@ -1401,7 +1397,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 0 second = 1 - add.width_hidden = 100.0 elif nodes_list == selected_z: add = nodes.new('CompositorNodeZcombine') add.show_preview = False @@ -1410,7 +1405,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 0 second = 2 - add.width_hidden = 100.0 elif nodes_list == selected_alphaover: add = nodes.new('CompositorNodeAlphaOver') add.show_preview = False @@ -1419,7 +1413,6 @@ class NWMergeNodes(Operator, NWBase): loc_y = loc_y - 50 first = 1 second = 2 - add.width_hidden = 100.0 add.location = loc_x, loc_y loc_y += offset_y add.select = True @@ -2184,7 +2177,6 @@ class NWAddReroutes(Operator, NWBase): # unhide 'REROUTE' nodes to avoid issues with location.y if node.type == 'REROUTE': node.hide = False - # When node is hidden - width_hidden not usable. # Hack needed to calculate real width if node.hide: bpy.ops.node.select_all(action='DESELECT') @@ -2726,7 +2718,6 @@ class NWAddMultipleImages(Operator, NWBase, ImportHelper): new_nodes.append(node) node.label = fname node.hide = True - node.width_hidden = 100 node.location.x = xloc node.location.y = yloc yloc -= 40 diff --git a/object_carver/carver_utils.py b/object_carver/carver_utils.py index c605111fb..b264a0ff3 100644 --- a/object_carver/carver_utils.py +++ b/object_carver/carver_utils.py @@ -308,11 +308,16 @@ def CreateBevel(context, CurrentObject): bpy.ops.object.mode_set(mode='OBJECT') - CurrentObject.data.use_customdata_edge_bevel = True + bevel_weights = CurrentObject.data.attributes["bevel_weight_edge"] + if not bevel_weights: + bevel_weights = CurrentObject.data.attributes.new("bevel_weight_edge", 'FLOAT', 'EDGE') + if bevel_weights.data_type != 'FLOAT' or bevel_weights.domain != 'EDGE': + bevel_weights = None for i in range(len(CurrentObject.data.edges)): if CurrentObject.data.edges[i].select is True: - CurrentObject.data.edges[i].bevel_weight = 1.0 + if bevel_weights: + bevel_weights.data[i] = 1.0 CurrentObject.data.edges[i].use_edge_sharp = True bevel_modifier = False