diff options
Diffstat (limited to 'release/scripts/modules')
-rw-r--r-- | release/scripts/modules/bpy_extras/mesh_utils.py | 190 | ||||
-rw-r--r-- | release/scripts/modules/bpy_extras/node_shader_utils.py | 214 | ||||
-rw-r--r-- | release/scripts/modules/bpy_types.py | 36 | ||||
-rw-r--r-- | release/scripts/modules/rna_keymap_ui.py | 8 | ||||
-rw-r--r-- | release/scripts/modules/rna_prop_ui.py | 2 |
5 files changed, 243 insertions, 207 deletions
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py index a7872daca67..a09282da2fe 100644 --- a/release/scripts/modules/bpy_extras/mesh_utils.py +++ b/release/scripts/modules/bpy_extras/mesh_utils.py @@ -20,13 +20,12 @@ __all__ = ( "mesh_linked_uv_islands", - "mesh_linked_tessfaces", + "mesh_linked_triangles", "edge_face_count_dict", "edge_face_count", - "edge_loops_from_tessfaces", "edge_loops_from_edges", "ngon_tessellate", - "face_random_points", + "triangle_random_points", ) @@ -90,41 +89,41 @@ def mesh_linked_uv_islands(mesh): return poly_islands -def mesh_linked_tessfaces(mesh): +def mesh_linked_triangles(mesh): """ - Splits the mesh into connected faces, use this for separating cubes from + Splits the mesh into connected triangles, use this for separating cubes from other mesh elements within 1 mesh datablock. :arg mesh: the mesh used to group with. :type mesh: :class:`bpy.types.Mesh` - :return: lists of lists containing faces. + :return: lists of lists containing triangles. :rtype: list """ # Build vert face connectivity - vert_faces = [[] for i in range(len(mesh.vertices))] - for f in mesh.tessfaces: - for v in f.vertices: - vert_faces[v].append(f) + vert_tris = [[] for i in range(len(mesh.vertices))] + for t in mesh.loop_triangles: + for v in t.vertices: + vert_tris[v].append(t) - # sort faces into connectivity groups - face_groups = [[f] for f in mesh.tessfaces] - # map old, new face location - face_mapping = list(range(len(mesh.tessfaces))) + # sort triangles into connectivity groups + tri_groups = [[t] for t in mesh.loop_triangles] + # map old, new tri location + tri_mapping = list(range(len(mesh.loop_triangles))) - # Now clump faces iteratively + # Now clump triangles iteratively ok = True while ok: ok = False - for i, f in enumerate(mesh.tessfaces): - mapped_index = face_mapping[f.index] - mapped_group = face_groups[mapped_index] + for i, t in enumerate(mesh.loop_triangles): + mapped_index = tri_mapping[t.index] + mapped_group = tri_groups[mapped_index] - for v in f.vertices: - for nxt_f in vert_faces[v]: - if nxt_f != f: - nxt_mapped_index = face_mapping[nxt_f.index] + for v in t.vertices: + for nxt_t in vert_tris[v]: + if nxt_t != t: + nxt_mapped_index = tri_mapping[nxt_t.index] # We are not a part of the same group if mapped_index != nxt_mapped_index: @@ -132,18 +131,18 @@ def mesh_linked_tessfaces(mesh): # Assign mapping to this group so they # all map to this group - for grp_f in face_groups[nxt_mapped_index]: - face_mapping[grp_f.index] = mapped_index + for grp_t in tri_groups[nxt_mapped_index]: + tri_mapping[grp_t.index] = mapped_index - # Move faces into this group - mapped_group.extend(face_groups[nxt_mapped_index]) + # Move triangles into this group + mapped_group.extend(tri_groups[nxt_mapped_index]) # remove reference to the list - face_groups[nxt_mapped_index] = None + tri_groups[nxt_mapped_index] = None - # return all face groups that are not null - # this is all the faces that are connected in their own lists. - return [fg for fg in face_groups if fg] + # return all tri groups that are not null + # this is all the triangles that are connected in their own lists. + return [tg for tg in tri_groups if tg] def edge_face_count_dict(mesh): @@ -177,87 +176,6 @@ def edge_face_count(mesh): return [get(edge_face_count, ed.key, 0) for ed in mesh.edges] -def edge_loops_from_tessfaces(mesh, tessfaces=None, seams=()): - """ - Edge loops defined by faces - - Takes me.tessfaces or a list of faces and returns the edge loops - These edge loops are the edges that sit between quads, so they don't touch - 1 quad, note: not connected will make 2 edge loops, - both only containing 2 edges. - - return a list of edge key lists - [[(0, 1), (4, 8), (3, 8)], ...] - - :arg mesh: the mesh used to get edge loops from. - :type mesh: :class:`bpy.types.Mesh` - :arg tessfaces: optional face list to only use some of the meshes faces. - :type tessfaces: :class:`bpy.types.MeshTessFace`, sequence or or NoneType - :return: return a list of edge vertex index lists. - :rtype: list - """ - - OTHER_INDEX = 2, 3, 0, 1 # opposite face index - - if tessfaces is None: - tessfaces = mesh.tessfaces - - edges = {} - - for f in tessfaces: - if len(f.vertices) == 4: - edge_keys = f.edge_keys - for i, edkey in enumerate(f.edge_keys): - edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]]) - - for edkey in seams: - edges[edkey] = [] - - # Collect edge loops here - edge_loops = [] - - for edkey, ed_adj in edges.items(): - if 0 < len(ed_adj) < 3: # 1 or 2 - # Seek the first edge - context_loop = [edkey, ed_adj[0]] - edge_loops.append(context_loop) - if len(ed_adj) == 2: - other_dir = ed_adj[1] - else: - other_dir = None - - del ed_adj[:] - - flipped = False - - while 1: - # from knowing the last 2, look for the next. - ed_adj = edges[context_loop[-1]] - if len(ed_adj) != 2: - # the original edge had 2 other edges - if other_dir and flipped is False: - flipped = True # only flip the list once - context_loop.reverse() - del ed_adj[:] - context_loop.append(other_dir) # save 1 look-up - - ed_adj = edges[context_loop[-1]] - if len(ed_adj) != 2: - del ed_adj[:] - break - else: - del ed_adj[:] - break - - i = ed_adj.index(context_loop[-2]) - context_loop.append(ed_adj[not i]) - - # Don't look at this again - del ed_adj[:] - - return edge_loops - - def edge_loops_from_edges(mesh, edges=None): """ Edge loops defined by edges @@ -511,54 +429,42 @@ def ngon_tessellate(from_data, indices, fix_loops=True): return fill -def face_random_points(num_points, tessfaces): +def triangle_random_points(num_points, loop_triangles): """ - Generates a list of random points over mesh tessfaces. + Generates a list of random points over mesh loop triangles. - :arg num_points: the number of random points to generate on each face. + :arg num_points: the number of random points to generate on each triangle. :type int: - :arg tessfaces: list of the faces to generate points on. - :type tessfaces: :class:`bpy.types.MeshTessFace`, sequence - :return: list of random points over all faces. + :arg loop_triangles: list of the triangles to generate points on. + :type loop_triangles: :class:`bpy.types.MeshLoopTriangle`, sequence + :return: list of random points over all triangles. :rtype: list """ from random import random from mathutils.geometry import area_tri - # Split all quads into 2 tris, tris remain unchanged - tri_faces = [] - for f in tessfaces: - tris = [] - verts = f.id_data.vertices - fv = f.vertices[:] - tris.append((verts[fv[0]].co, - verts[fv[1]].co, - verts[fv[2]].co, - )) - if len(fv) == 4: - tris.append((verts[fv[0]].co, - verts[fv[3]].co, - verts[fv[2]].co, - )) - tri_faces.append(tris) - - # For each face, generate the required number of random points - sampled_points = [None] * (num_points * len(tessfaces)) - for i, tf in enumerate(tri_faces): + # For each triangle, generate the required number of random points + sampled_points = [None] * (num_points * len(loop_triangles)) + for i, lt in enumerate(loop_triangles): + # Get triangle vertex coordinates + verts = lt.id_data.vertices + ltv = lt.vertices[:] + tv = (verts[ltv[0]].co, verts[ltv[1]].co, verts[ltv[2]].co) + for k in range(num_points): # If this is a quad, we need to weight its 2 tris by their area - if len(tf) != 1: - area1 = area_tri(*tf[0]) - area2 = area_tri(*tf[1]) + if len(tv) != 1: + area1 = area_tri(*tv[0]) + area2 = area_tri(*tv[1]) area_tot = area1 + area2 area1 = area1 / area_tot area2 = area2 / area_tot - vecs = tf[0 if (random() < area1) else 1] + vecs = tv[0 if (random() < area1) else 1] else: - vecs = tf[0] + vecs = tv[0] u1 = random() u2 = random() diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py index 456c38921a7..e97eac0a9e6 100644 --- a/release/scripts/modules/bpy_extras/node_shader_utils.py +++ b/release/scripts/modules/bpy_extras/node_shader_utils.py @@ -19,7 +19,7 @@ # <pep8 compliant> import bpy -from mathutils import Vector +from mathutils import Color, Vector __all__ = ( "PrincipledBSDFWrapper", @@ -37,6 +37,12 @@ def _set_check(func): return func(self, *args, **kwargs) return wrapper +def rgb_to_rgba(rgb): + return list(rgb) + [1.0] + +def rgba_to_rgb(rgba): + return Color((rgba[0], rgba[1], rgba[2])) + class ShaderWrapper(): """ @@ -85,9 +91,10 @@ class ShaderWrapper(): dst_node.width = min(dst_node.width, self._col_size - 20) return loc - def __init__(self, material, is_readonly=True): + def __init__(self, material, is_readonly=True, use_nodes=True): self.is_readonly = is_readonly self.material = material + self.use_nodes = use_nodes self.update() def update(self): # Should be re-implemented by children classes... @@ -96,6 +103,7 @@ class ShaderWrapper(): self._textures = {} self._grid_locations = set() + def use_nodes_get(self): return self.material.use_nodes @@ -103,17 +111,22 @@ class ShaderWrapper(): def use_nodes_set(self, val): self.material.use_nodes = val self.update() + use_nodes = property(use_nodes_get, use_nodes_set) + def node_texcoords_get(self): if not self.use_nodes: return None - if self._node_texcoords is None: + if self._node_texcoords is ...: + # Running only once, trying to find a valid texcoords node. for n in self.material.node_tree.nodes: if n.bl_idname == 'ShaderNodeTexCoord': self._node_texcoords = n self._grid_to_location(0, 0, ref_node=n) break + if self._node_texcoords is ...: + self._node_texcoords = None if self._node_texcoords is None and not self.is_readonly: tree = self.material.node_tree nodes = tree.nodes @@ -124,6 +137,7 @@ class ShaderWrapper(): self._grid_to_location(-5, 1, dst_node=node_texcoords) self._node_texcoords = node_texcoords return self._node_texcoords + node_texcoords = property(node_texcoords_get) @@ -149,8 +163,9 @@ class PrincipledBSDFWrapper(ShaderWrapper): NODES_LIST = ShaderWrapper.NODES_LIST + NODES_LIST - def __init__(self, material, is_readonly=True): - super(PrincipledBSDFWrapper, self).__init__(material, is_readonly) + def __init__(self, material, is_readonly=True, use_nodes=True): + super(PrincipledBSDFWrapper, self).__init__(material, is_readonly, use_nodes) + def update(self): super(PrincipledBSDFWrapper, self).update() @@ -206,47 +221,60 @@ class PrincipledBSDFWrapper(ShaderWrapper): # -------------------------------------------------------------------- # Normal Map, lazy initialization... - self._node_normalmap = None + self._node_normalmap = ... # -------------------------------------------------------------------- # Tex Coords, lazy initialization... - self._node_texcoords = None + self._node_texcoords = ... + def node_normalmap_get(self): if not self.use_nodes: return None - if self._node_normalmap is None and self.node_principled_bsdf is not None: + if self.node_principled_bsdf is not None: node_principled = self.node_principled_bsdf - if node_principled.inputs["Normal"].is_linked: - node_normalmap = node_principled.inputs["Normal"].links[0].from_node - if node_normalmap.bl_idname == 'ShaderNodeNormalMap': - self._node_normalmap = node_normalmap - self._grid_to_location(0, 0, ref_node=node_normalmap) + if self._node_normalmap is ...: + # Running only once, trying to find a valid normalmap node. + if node_principled.inputs["Normal"].is_linked: + node_normalmap = node_principled.inputs["Normal"].links[0].from_node + if node_normalmap.bl_idname == 'ShaderNodeNormalMap': + self._node_normalmap = node_normalmap + self._grid_to_location(0, 0, ref_node=node_normalmap) + if self._node_normalmap is ...: + self._node_normalmap = None if self._node_normalmap is None and not self.is_readonly: + tree = self.material.node_tree + nodes = tree.nodes + links = tree.links + node_normalmap = nodes.new(type='ShaderNodeNormalMap') node_normalmap.label = "Normal/Map" self._grid_to_location(-1, -2, dst_node=node_normalmap, ref_node=node_principled) # Link links.new(node_normalmap.outputs["Normal"], node_principled.inputs["Normal"]) return self._node_normalmap + node_normalmap = property(node_normalmap_get) + # -------------------------------------------------------------------- - # Diffuse. + # Base Color. - def diffuse_color_get(self): + def base_color_get(self): if not self.use_nodes or self.node_principled_bsdf is None: return self.material.diffuse_color - return self.node_principled_bsdf.inputs["Base Color"].default_value + return rgba_to_rgb(self.node_principled_bsdf.inputs["Base Color"].default_value) @_set_check - def diffuse_color_set(self, color): + def base_color_set(self, color): self.material.diffuse_color = color if self.use_nodes and self.node_principled_bsdf is not None: - self.node_principled_bsdf.inputs["Base Color"].default_value = color - diffuse_color = property(diffuse_color_get, diffuse_color_set) + self.node_principled_bsdf.inputs["Base Color"].default_value = rgb_to_rgba(color) + + base_color = property(base_color_get, base_color_set) + - def diffuse_texture_get(self): + def base_color_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: return None return ShaderImageTextureWrapper( @@ -254,7 +282,9 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_principled_bsdf.inputs["Base Color"], grid_row_diff=1, ) - diffuse_texture = property(diffuse_texture_get) + + base_color_texture = property(base_color_texture_get) + # -------------------------------------------------------------------- # Specular. @@ -269,30 +299,37 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.material.specular_intensity = value if self.use_nodes and self.node_principled_bsdf is not None: self.node_principled_bsdf.inputs["Specular"].default_value = value + specular = property(specular_get, specular_set) + def specular_tint_get(self): if not self.use_nodes or self.node_principled_bsdf is None: return 0.0 - return self.node_principled_bsdf.inputs["Specular Tint"].default_value + return rgba_to_rgb(self.node_principled_bsdf.inputs["Specular Tint"].default_value) @_set_check def specular_tint_set(self, value): if self.use_nodes and self.node_principled_bsdf is not None: - self.node_principled_bsdf.inputs["Specular Tint"].default_value = value + self.node_principled_bsdf.inputs["Specular Tint"].default_value = rgb_to_rgba(value) + specular_tint = property(specular_tint_get, specular_tint_set) + # Will only be used as gray-scale one... def specular_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: + print("NO NODES!") return None return ShaderImageTextureWrapper( self, self.node_principled_bsdf, self.node_principled_bsdf.inputs["Specular"], grid_row_diff=0, ) + specular_texture = property(specular_texture_get) + # -------------------------------------------------------------------- # Roughness (also sort of inverse of specular hardness...). @@ -306,8 +343,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.material.roughness = value if self.use_nodes and self.node_principled_bsdf is not None: self.node_principled_bsdf.inputs["Roughness"].default_value = value + roughness = property(roughness_get, roughness_set) + # Will only be used as gray-scale one... def roughness_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: @@ -317,8 +356,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_principled_bsdf.inputs["Roughness"], grid_row_diff=0, ) + roughness_texture = property(roughness_texture_get) + # -------------------------------------------------------------------- # Metallic (a.k.a reflection, mirror). @@ -332,8 +373,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.material.metallic = value if self.use_nodes and self.node_principled_bsdf is not None: self.node_principled_bsdf.inputs["Metallic"].default_value = value + metallic = property(metallic_get, metallic_set) + # Will only be used as gray-scale one... def metallic_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: @@ -343,8 +386,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_principled_bsdf.inputs["Metallic"], grid_row_diff=0, ) + metallic_texture = property(metallic_texture_get) + # -------------------------------------------------------------------- # Transparency settings. @@ -357,8 +402,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): def ior_set(self, value): if self.use_nodes and self.node_principled_bsdf is not None: self.node_principled_bsdf.inputs["IOR"].default_value = value + ior = property(ior_get, ior_set) + # Will only be used as gray-scale one... def ior_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: @@ -368,8 +415,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_principled_bsdf.inputs["IOR"], grid_row_diff=-1, ) + ior_texture = property(ior_texture_get) + def transmission_get(self): if not self.use_nodes or self.node_principled_bsdf is None: return 0.0 @@ -379,8 +428,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): def transmission_set(self, value): if self.use_nodes and self.node_principled_bsdf is not None: self.node_principled_bsdf.inputs["Transmission"].default_value = value + transmission = property(transmission_get, transmission_set) + # Will only be used as gray-scale one... def transmission_texture_get(self): if not self.use_nodes or self.node_principled_bsdf is None: @@ -390,8 +441,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_principled_bsdf.inputs["Transmission"], grid_row_diff=-1, ) + transmission_texture = property(transmission_texture_get) + # TODO: Do we need more complex handling for alpha (allowing masking and such)? # Would need extra mixing nodes onto Base Color maybe, or even its own shading chain... @@ -407,8 +460,10 @@ class PrincipledBSDFWrapper(ShaderWrapper): def normalmap_strength_set(self, value): if self.use_nodes and self.node_normalmap is not None: self.node_normalmap.inputs["Strength"].default_value = value + normalmap_strength = property(normalmap_strength_get, normalmap_strength_set) + def normalmap_texture_get(self): if not self.use_nodes or self.node_normalmap is None: return None @@ -417,9 +472,11 @@ class PrincipledBSDFWrapper(ShaderWrapper): self.node_normalmap.inputs["Color"], grid_row_diff=-2, ) + normalmap_texture = property(normalmap_texture_get) + class ShaderImageTextureWrapper(): """ Generic 'image texture'-like wrapper, handling image node, some mapping (texture coordinates transformations), @@ -460,15 +517,17 @@ class ShaderImageTextureWrapper(): self.grid_row_diff = grid_row_diff self.use_alpha = use_alpha - self._node_image = None - self._node_mapping = None + self._node_image = ... + self._node_mapping = ... tree = node_dst.id_data nodes = tree.nodes links = tree.links if socket_dst.is_linked: - self._node_image = socket_dst.links[0].from_node + from_node = socket_dst.links[0].from_node + if from_node.bl_idname == 'ShaderNodeTexImage': + self._node_image = from_node if self.node_image is not None: socket_dst = self.node_image.inputs["Vector"] @@ -477,16 +536,67 @@ class ShaderImageTextureWrapper(): if from_node.bl_idname == 'ShaderNodeMapping': self._node_mapping = from_node + + def copy_from(self, tex): + # Avoid generating any node in source texture. + is_readonly_back = tex.is_readonly + tex.is_readonly = True + + if tex.node_image is not None: + self.image = tex.image + self.projection = tex.projection + self.texcoords = tex.texcoords + self.copy_mapping_from(tex) + + tex.is_readonly = is_readonly_back + + + def copy_mapping_from(self, tex): + # Avoid generating any node in source texture. + is_readonly_back = tex.is_readonly + tex.is_readonly = True + + if tex.node_mapping is None: # Used to actually remove mapping node. + if self.has_mapping_node(): + # We assume node_image can never be None in that case... + # Find potential existing link into image's Vector input. + socket_dst = socket_src = None + if self.node_mapping.inputs["Vector"].is_linked: + socket_dst = self.node_image.inputs["Vector"] + socket_src = self.node_mapping.inputs["Vector"].links[0].from_socket + + tree = self.owner_shader.material.node_tree + tree.nodes.remove(self.node_mapping) + self._node_mapping = None + + # If previously existing, re-link texcoords -> image + if socket_src is not None: + tree.links.new(socket_src, socket_dst) + elif self.node_mapping is not None: + self.translation = tex.translation + self.rotation = tex.rotation + self.scale = tex.scale + self.use_min = tex.use_min + self.use_max = tex.use_max + self.min = tex.min + self.max = tex.max + + tex.is_readonly = is_readonly_back + + # -------------------------------------------------------------------- # Image. def node_image_get(self): - if self._node_image is None: + if self._node_image is ...: + # Running only once, trying to find a valid image node. if self.socket_dst.is_linked: node_image = self.socket_dst.links[0].from_node if node_image.bl_idname == 'ShaderNodeTexImage': self._node_image = node_image self.owner_shader._grid_to_location(0, 0, ref_node=node_image) + if self._node_image is ...: + self._node_image = None if self._node_image is None and not self.is_readonly: tree = self.owner_shader.material.node_tree @@ -497,45 +607,61 @@ class ShaderImageTextureWrapper(): self._node_image = node_image return self._node_image + node_image = property(node_image_get) + def image_get(self): return self.node_image.image if self.node_image is not None else None @_set_check def image_set(self, image): self.node_image.image = image + image = property(image_get, image_set) + def projection_get(self): return self.node_image.projection if self.node_image is not None else 'FLAT' @_set_check def projection_set(self, projection): self.node_image.projection = projection + projection = property(projection_get, projection_set) + def texcoords_get(self): if self.node_image is not None: - socket = (self.node_mapping if self._node_mapping is not None else self.node_image).inputs["Vector"] + socket = (self.node_mapping if self.has_mapping_node() else self.node_image).inputs["Vector"] if socket.is_linked: return socket.links[0].from_socket.name return 'UV' @_set_check def texcoords_set(self, texcoords): + # Image texture node already defaults to UVs, no extra node needed. + # ONLY in case we do not have any texcoords mapping!!! + if texcoords == 'UV' and not self.has_mapping_node(): + return tree = self.node_image.id_data links = tree.links - node_dst = self.node_mapping if self._node_mapping is not None else self.node_image + node_dst = self.node_mapping if self.has_mapping_node() else self.node_image socket_src = self.owner_shader.node_texcoords.outputs[texcoords] links.new(socket_src, node_dst.inputs["Vector"]) + texcoords = property(texcoords_get, texcoords_set) + # -------------------------------------------------------------------- # Mapping. + def has_mapping_node(self): + return self._node_mapping not in {None, ...} + def node_mapping_get(self): - if self._node_mapping is None: + if self._node_mapping is ...: + # Running only once, trying to find a valid mapping node. if self.node_image is None: return None if self.node_image.inputs["Vector"].is_linked: @@ -543,78 +669,96 @@ class ShaderImageTextureWrapper(): if node_mapping.bl_idname == 'ShaderNodeMapping': self._node_mapping = node_mapping self.owner_shader._grid_to_location(0, 0 + self.grid_row_diff, ref_node=node_mapping) + if self._node_mapping is ...: + self._node_mapping = None if self._node_mapping is None and not self.is_readonly: # Find potential existing link into image's Vector input. socket_dst = self.node_image.inputs["Vector"] - socket_src = socket_dst.links[0].from_socket if socket_dst.is_linked else None + # If not already existing, we need to create texcoords -> mapping link (from UV). + socket_src = (socket_dst.links[0].from_socket if socket_dst.is_linked + else self.owner_shader.node_texcoords.outputs['UV']) tree = self.owner_shader.material.node_tree node_mapping = tree.nodes.new(type='ShaderNodeMapping') node_mapping.vector_type = 'TEXTURE' self.owner_shader._grid_to_location(-1, 0, dst_node=node_mapping, ref_node=self.node_image) - # link mapping -> image node + # Link mapping -> image node. tree.links.new(node_mapping.outputs["Vector"], socket_dst) - # And if already existing, re-link texcoords -> mapping - if socket_src is not None: - tree.links.new(socket_src, node_mapping.inputs["Vector"]) + # Link texcoords -> mapping. + tree.links.new(socket_src, node_mapping.inputs["Vector"]) self._node_mapping = node_mapping return self._node_mapping + node_mapping = property(node_mapping_get) + def translation_get(self): return self.node_mapping.translation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0)) @_set_check def translation_set(self, translation): self.node_mapping.translation = translation + translation = property(translation_get, translation_set) + def rotation_get(self): return self.node_mapping.rotation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0)) @_set_check def rotation_set(self, rotation): self.node_mapping.rotation = rotation + rotation = property(rotation_get, rotation_set) + def scale_get(self): return self.node_mapping.scale if self.node_mapping is not None else Vector((1.0, 1.0, 1.0)) @_set_check def scale_set(self, scale): self.node_mapping.scale = scale + scale = property(scale_get, scale_set) + def use_min_get(self): return self.node_mapping.use_min if self_mapping.node is not None else False @_set_check def use_min_set(self, use_min): self.node_mapping.use_min = use_min + use_min = property(use_min_get, use_min_set) + def use_max_get(self): return self.node_mapping.use_max if self_mapping.node is not None else False @_set_check def use_max_set(self, use_max): self.node_mapping.use_max = use_max + use_max = property(use_max_get, use_max_set) + def min_get(self): return self.node_mapping.min if self.node_mapping is not None else Vector((0.0, 0.0, 0.0)) @_set_check def min_set(self, min): self.node_mapping.min = min + min = property(min_get, min_set) + def max_get(self): return self.node_mapping.max if self.node_mapping is not None else Vector((0.0, 0.0, 0.0)) @_set_check def max_set(self, max): self.node_mapping.max = max + max = property(max_get, max_set) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 52dce466800..9fe45d223f5 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -468,7 +468,7 @@ class MeshEdge(StructRNA): return ord_ind(*tuple(self.vertices)) -class MeshTessFace(StructRNA): +class MeshLoopTriangle(StructRNA): __slots__ = () @property @@ -476,32 +476,18 @@ class MeshTessFace(StructRNA): """The midpoint of the face.""" face_verts = self.vertices[:] mesh_verts = self.id_data.vertices - if len(face_verts) == 3: - return (mesh_verts[face_verts[0]].co + - mesh_verts[face_verts[1]].co + - mesh_verts[face_verts[2]].co - ) / 3.0 - else: - return (mesh_verts[face_verts[0]].co + - mesh_verts[face_verts[1]].co + - mesh_verts[face_verts[2]].co + - mesh_verts[face_verts[3]].co - ) / 4.0 + return (mesh_verts[face_verts[0]].co + + mesh_verts[face_verts[1]].co + + mesh_verts[face_verts[2]].co + ) / 3.0 @property def edge_keys(self): verts = self.vertices[:] - if len(verts) == 3: - return (ord_ind(verts[0], verts[1]), - ord_ind(verts[1], verts[2]), - ord_ind(verts[2], verts[0]), - ) - else: - return (ord_ind(verts[0], verts[1]), - ord_ind(verts[1], verts[2]), - ord_ind(verts[2], verts[3]), - ord_ind(verts[3], verts[0]), - ) + return (ord_ind(verts[0], verts[1]), + ord_ind(verts[1], verts[2]), + ord_ind(verts[2], verts[0]), + ) class MeshPolygon(StructRNA): @@ -887,7 +873,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): props.menu_idname = self.bl_idname if add_operator: - props = row.operator(add_operator, text="", icon='ZOOMOUT') + props = row.operator(add_operator, text="", icon='REMOVE') props.name = name props.remove_name = True @@ -901,7 +887,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): sub.emboss = 'NORMAL' sub.prop(wm, "preset_name", text="") - props = row.operator(add_operator, text="", icon='ZOOMIN') + props = row.operator(add_operator, text="", icon='ADD') props.name = wm.preset_name def draw_preset(self, context): diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py index 2581d7782f1..752db7fd5ac 100644 --- a/release/scripts/modules/rna_keymap_ui.py +++ b/release/scripts/modules/rna_keymap_ui.py @@ -105,7 +105,7 @@ def draw_km(display_keymaps, kc, km, children, layout, level): subcol = _indented_layout(col, kmi_level) subcol = subcol.split(factor=0.2).column() subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager, - icon='ZOOMIN') + icon='ADD') col.separator() @@ -350,7 +350,7 @@ def draw_filtered(display_keymaps, filter_type, filter_text, layout): # "Add New" at end of keymap item list col = _indented_layout(layout, 1) subcol = col.split(factor=0.2).column() - subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN') + subcol.operator("wm.keyitem_add", text="Add New", icon='ADD') return True @@ -380,8 +380,8 @@ def draw_keymaps(context, layout): if not text: text = "Blender (default)" row.menu("USERPREF_MT_keyconfigs", text=text) - row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMIN') - row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMOUT').remove_active = True + row.operator("wm.keyconfig_preset_add", text="", icon='ADD') + row.operator("wm.keyconfig_preset_add", text="", icon='REMOVE').remove_active = True # layout.context_pointer_set("keyconfig", wm.keyconfigs.active) # row.operator("wm.keyconfig_remove", text="", icon='X') diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index c987609bafa..fc17cc60c6c 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -188,7 +188,7 @@ def draw(layout, context, context_member, property_type, use_edit=True): if not is_rna: props = row.operator("wm.properties_edit", text="Edit") assign_props(props, val_draw, key) - props = row.operator("wm.properties_remove", text="", icon='ZOOMOUT') + props = row.operator("wm.properties_remove", text="", icon='REMOVE') assign_props(props, val_draw, key) else: row.label(text="API Defined") |