Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Mueller <nexyon@gmail.com>2011-06-21 02:55:18 +0400
committerJoerg Mueller <nexyon@gmail.com>2011-06-21 02:55:18 +0400
commit207911bdb3e5ba3e110cc7107186af988d2d10e8 (patch)
tree88684071e2813d52f8dc700b593d7644b2be88c8 /release/scripts
parentadb81a0351c0854ee8529ae7a66ef9c907790ee5 (diff)
parent768184753abb5a69e278bfe6207fe070b2e0ffc7 (diff)
Merge with trunk r37677
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/modules/bpy_extras/mesh_utils.py1
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py2
-rw-r--r--release/scripts/modules/bpy_types.py4
-rw-r--r--release/scripts/modules/rna_prop_ui.py14
-rw-r--r--release/scripts/startup/bl_operators/nla.py123
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py110
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_data_metaball.py17
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
11 files changed, 218 insertions, 80 deletions
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py
index b6d8a1fcf16..e026910fb43 100644
--- a/release/scripts/modules/bpy_extras/mesh_utils.py
+++ b/release/scripts/modules/bpy_extras/mesh_utils.py
@@ -267,6 +267,7 @@ def ngon_tesselate(from_data, indices, fix_loops=True):
fix_loops: If this is enabled polylines that use loops to make multiple polylines are delt with correctly.
'''
+ from mathutils.geometry import tesselate_polygon
from mathutils import Vector
vector_to_tuple = Vector.to_tuple
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index 45f537ebd2f..f2f2e53240b 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -114,6 +114,8 @@ def location_3d_to_region_2d(region, rv3d, coord):
:return: 2d location
:rtype: :class:`Vector`
"""
+ from mathutils import Vector
+
prj = Vector((coord[0], coord[1], coord[2], 1.0)) * rv3d.perspective_matrix
if prj.w > 0.0:
width_half = region.width / 2.0
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index c30c893c9cc..c33ec2df86f 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -20,7 +20,6 @@
from _bpy import types as bpy_types
import _bpy
-from mathutils import Vector
StructRNA = bpy_types.Struct.__bases__[0]
StructMetaPropGroup = _bpy.StructMetaPropGroup
@@ -144,18 +143,21 @@ class _GenericBone:
def x_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
+ from mathutils import Vector
return Vector((1.0, 0.0, 0.0)) * self.matrix.to_3x3()
@property
def y_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
+ from mathutils import Vector
return Vector((0.0, 1.0, 0.0)) * self.matrix.to_3x3()
@property
def z_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
+ from mathutils import Vector
return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3()
@property
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 9311987e2e7..b0fb3b66d0a 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -111,12 +111,16 @@ def draw(layout, context, context_member, property_type, use_edit=True):
continue
row = layout.row()
- convert_to_pyobject = getattr(val, "convert_to_pyobject", None)
+ to_dict = getattr(val, "to_dict", None)
+ to_list = getattr(val, "to_list", None)
val_orig = val
- if convert_to_pyobject:
- val_draw = val = val.convert_to_pyobject()
- val_draw = str(val_draw)
+ if to_dict:
+ val = to_dict()
+ val_draw = str(val)
+ elif to_list:
+ val = to_list()
+ val_draw = str(val)
else:
val_draw = val
@@ -131,7 +135,7 @@ def draw(layout, context, context_member, property_type, use_edit=True):
row.label(text=key)
# explicit exception for arrays
- if convert_to_pyobject and not hasattr(val_orig, "len"):
+ if to_dict or to_list:
row.label(text=val_draw)
else:
if key in rna_properties:
diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py
index 82849cca2cc..a895916ca92 100644
--- a/release/scripts/startup/bl_operators/nla.py
+++ b/release/scripts/startup/bl_operators/nla.py
@@ -16,17 +16,16 @@
#
# ##### END GPL LICENSE BLOCK #####
-# <pep8 compliant>
+# <pep8-80 compliant>
import bpy
-def pose_info():
+def pose_frame_info(obj):
from mathutils import Matrix
info = {}
- obj = bpy.context.object
pose = obj.pose
pose_items = pose.bones.items()
@@ -51,7 +50,6 @@ def pose_info():
except:
binfo["matrix_pose_inv"] = Matrix()
- print(binfo["matrix_pose"])
info[name] = binfo
for name, pbone in pose_items:
@@ -67,45 +65,86 @@ def pose_info():
matrix = binfo_parent["matrix_pose_inv"] * matrix
rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
- matrix = rest_matrix.inverted() * matrix
+ binfo["matrix_key"] = rest_matrix.inverted() * matrix
+
+ return info
- binfo["matrix_key"] = matrix.copy()
+def obj_frame_info(obj):
+ info = {}
+ # parent = obj.parent
+ info["matrix_key"] = obj.matrix_local.copy()
return info
-def bake(frame_start, frame_end, step=1, only_selected=False):
+def bake(frame_start,
+ frame_end, step=1,
+ only_selected=False,
+ do_pose=True,
+ do_object=True,
+ do_constraint_clear=False,
+ ):
+
scene = bpy.context.scene
obj = bpy.context.object
pose = obj.pose
+ frame_back = scene.frame_current
+
+ if pose is None:
+ do_pose = False
- info_ls = []
+ if do_pose is None and do_object is None:
+ return None
+
+ pose_info = []
+ obj_info = []
frame_range = range(frame_start, frame_end + 1, step)
- # could spped this up by applying steps here too...
+ # -------------------------------------------------------------------------
+ # Collect transformations
+
+ # could speed this up by applying steps here too...
for f in frame_range:
scene.frame_set(f)
- info = pose_info()
- info_ls.append(info)
+ if do_pose:
+ pose_info.append(pose_frame_info(obj))
+ if do_object:
+ obj_info.append(obj_frame_info(obj))
+
f += 1
+ # -------------------------------------------------------------------------
+ # Create action
+
+ # incase animation data hassnt been created
+ atd = obj.animation_data_create()
action = bpy.data.actions.new("Action")
+ atd.action = action
- bpy.context.object.animation_data.action = action
+ if do_pose:
+ pose_items = pose.bones.items()
+ else:
+ pose_items = [] # skip
- pose_items = pose.bones.items()
+ # -------------------------------------------------------------------------
+ # Apply transformations to action
- for name, pbone in pose_items:
+ # pose
+ for name, pbone in (pose_items if do_pose else ()):
if only_selected and not pbone.bone.select:
continue
+ if do_constraint_clear:
+ while pbone.constraints:
+ pbone.constraints.remove(pbone.constraints[0])
+
for f in frame_range:
- matrix = info_ls[int((f - frame_start) / step)][name]["matrix_key"]
+ matrix = pose_info[(f - frame_start) // step][name]["matrix_key"]
- #pbone.location = matrix.to_translation()
- #pbone.rotation_quaternion = matrix.to_quaternion()
+ # pbone.location = matrix.to_translation()
+ # pbone.rotation_quaternion = matrix.to_quaternion()
pbone.matrix_basis = matrix
pbone.keyframe_insert("location", -1, f, name)
@@ -121,10 +160,35 @@ def bake(frame_start, frame_end, step=1, only_selected=False):
pbone.keyframe_insert("scale", -1, f, name)
+ # object. TODO. multiple objects
+ if do_object:
+ if do_constraint_clear:
+ while obj.constraints:
+ obj.constraints.remove(obj.constraints[0])
+
+ for f in frame_range:
+ matrix = obj_info[(f - frame_start) // step]["matrix_key"]
+ obj.matrix_local = matrix
+
+ obj.keyframe_insert("location", -1, f)
+
+ rotation_mode = obj.rotation_mode
+
+ if rotation_mode == 'QUATERNION':
+ obj.keyframe_insert("rotation_quaternion", -1, f)
+ elif rotation_mode == 'AXIS_ANGLE':
+ obj.keyframe_insert("rotation_axis_angle", -1, f)
+ else: # euler, XYZ, ZXY etc
+ obj.keyframe_insert("rotation_euler", -1, f)
+
+ obj.keyframe_insert("scale", -1, f)
+
+ scene.frame_set(frame_back)
+
return action
-from bpy.props import IntProperty, BoolProperty
+from bpy.props import IntProperty, BoolProperty, EnumProperty
class BakeAction(bpy.types.Operator):
@@ -144,10 +208,31 @@ class BakeAction(bpy.types.Operator):
default=1, min=1, max=120)
only_selected = BoolProperty(name="Only Selected",
default=True)
+ clear_consraints = BoolProperty(name="Clear Constraints",
+ default=False)
+ bake_types = EnumProperty(
+ name="Bake Data",
+ options={'ENUM_FLAG'},
+ items=(('POSE', "Pose", ""),
+ ('OBJECT', "Object", ""),
+ ),
+ default={'POSE'},
+ )
def execute(self, context):
- action = bake(self.frame_start, self.frame_end, self.step, self.only_selected)
+ action = bake(self.frame_start,
+ self.frame_end,
+ self.step,
+ self.only_selected,
+ 'POSE' in self.bake_types,
+ 'OBJECT' in self.bake_types,
+ self.clear_consraints,
+ )
+
+ if action is None:
+ self.report({'INFO'}, "Nothing to bake")
+ return {'CANCELLED'}
# basic cleanup, could move elsewhere
for fcu in action.fcurves:
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 90b0fa0af83..2ecca8ab168 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -22,6 +22,24 @@ from mathutils import Vector
import bpy
from bpy.props import BoolProperty, EnumProperty, IntProperty, FloatProperty, FloatVectorProperty
+
+def object_ensure_material(obj, mat_name):
+ """ Use an existing material or add a new one.
+ """
+ mat = mat_slot = None
+ for mat_slot in obj.material_slots:
+ mat = mat_slot.material
+ if mat:
+ break
+ if mat is None:
+ mat = bpy.data.materials.new(mat_name)
+ if mat_slot:
+ mat_slot.material = mat
+ else:
+ obj.data.materials.append(mat)
+ return mat
+
+
class QuickFur(bpy.types.Operator):
bl_idname = "object.quick_fur"
bl_label = "Quick Fur"
@@ -78,6 +96,7 @@ class QuickFur(bpy.types.Operator):
return {'FINISHED'}
+
class QuickExplode(bpy.types.Operator):
bl_idname = "object.quick_explode"
bl_label = "Quick Explode"
@@ -93,40 +112,44 @@ class QuickExplode(bpy.types.Operator):
amount = IntProperty(name="Amount of pieces",
default=100, min=2, max=10000, soft_min=2, soft_max=10000)
- duration = IntProperty(name="Duration",
- default=50, min=1, max=10000, soft_min=1, soft_max=10000)
+ frame_duration = IntProperty(name="Duration",
+ default=50, min=1, max=300000, soft_min=1, soft_max=10000)
- start_frame = IntProperty(name="Start Frame",
- default=1, min=1, max=10000, soft_min=1, soft_max=10000)
+ frame_start = IntProperty(name="Start Frame",
+ default=1, min=1, max=300000, soft_min=1, soft_max=10000)
- end_frame = IntProperty(name="End Frame",
- default=10, min=1, max=10000, soft_min=1, soft_max=10000)
+ frame_end = IntProperty(name="End Frame",
+ default=10, min=1, max=300000, soft_min=1, soft_max=10000)
velocity = FloatProperty(name="Outwards Velocity",
- default=1, min=0, max=1000, soft_min=0, soft_max=10)
+ default=1, min=0, max=300000, soft_min=0, soft_max=10)
fade = BoolProperty(name="Fade",
description="Fade the pieces over time.",
default=True)
- invert_order = BoolProperty(name="Invert Order",
- description="Blend objects in the opposite direction (only for Blend style explosion).",
- default=False)
-
def execute(self, context):
fake_context = bpy.context.copy()
- mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
+ obj_act = context.active_object
+
+ if obj_act.type != 'MESH':
+ self.report({'ERROR'}, "Active object is not a mesh")
+ return {'CANCELLED'}
+
+ mesh_objects = [obj for obj in context.selected_objects
+ if obj.type == 'MESH' and obj != obj_act]
+ mesh_objects.insert(0, obj_act)
if self.style == 'BLEND' and len(mesh_objects) != 2:
- self.report({'ERROR'}, "Select two mesh objects.")
+ self.report({'ERROR'}, "Select two mesh objects")
return {'CANCELLED'}
elif not mesh_objects:
- self.report({'ERROR'}, "Select at least one mesh object.")
+ self.report({'ERROR'}, "Select at least one mesh object")
return {'CANCELLED'}
for obj in mesh_objects:
- if len(obj.particle_systems) > 0:
- self.report({'ERROR'}, "Selected object's can't have particle systems.")
+ if obj.particle_systems:
+ self.report({'ERROR'}, "Object %r already has a particle system" % obj.name)
return {'CANCELLED'}
if self.fade:
@@ -137,16 +160,12 @@ class QuickExplode(bpy.types.Operator):
tex.color_ramp.elements[0].position = 0.333
tex.color_ramp.elements[1].position = 0.666
- tex.color_ramp.elements[0].color[3] = 1
- tex.color_ramp.elements[1].color[3] = 0
+ tex.color_ramp.elements[0].color[3] = 1.0
+ tex.color_ramp.elements[1].color[3] = 0.0
if self.style == 'BLEND':
- if self.invert_order:
- from_obj = mesh_objects[1]
- to_obj = mesh_objects[0]
- else:
- from_obj = mesh_objects[0]
- to_obj = mesh_objects[1]
+ from_obj = mesh_objects[1]
+ to_obj = mesh_objects[0]
for obj in mesh_objects:
fake_context["object"] = obj
@@ -154,31 +173,28 @@ class QuickExplode(bpy.types.Operator):
settings = obj.particle_systems[-1].settings
settings.count = self.amount
- settings.frame_start = self.start_frame
- settings.frame_end = self.end_frame - self.duration
- settings.lifetime = self.duration
+ settings.frame_start = self.frame_start
+ settings.frame_end = self.frame_end - self.frame_duration
+ settings.lifetime = self.frame_duration
settings.normal_factor = self.velocity
settings.render_type = 'NONE'
- bpy.ops.object.modifier_add(fake_context, type='EXPLODE')
- explode = obj.modifiers[-1]
+ explode = obj.modifiers.new(name='Explode', type='EXPLODE')
explode.use_edge_cut = True
if self.fade:
explode.show_dead = False
- bpy.ops.mesh.uv_texture_add(fake_context);
+ bpy.ops.mesh.uv_texture_add(fake_context)
uv = obj.data.uv_textures[-1]
uv.name = "Explode fade"
explode.particle_uv = uv.name
- if len(obj.material_slots) == 0:
- obj.data.materials.append(bpy.data.materials.new("Explode fade"))
+ mat = object_ensure_material(obj, "Explode Fade")
- mat = obj.data.materials[0]
mat.use_transparency = True
mat.use_transparent_shadows = True
- mat.alpha = 0
- mat.specular_alpha = 0
+ mat.alpha = 0.0
+ mat.specular_alpha = 0.0
tex_slot = mat.texture_slots.add()
@@ -190,16 +206,12 @@ class QuickExplode(bpy.types.Operator):
if self.style == 'BLEND':
if obj == to_obj:
- tex_slot.alpha_factor = -1
+ tex_slot.alpha_factor = -1.0
elem = tex.color_ramp.elements[1]
- elem.color[0] = mat.diffuse_color[0]
- elem.color[1] = mat.diffuse_color[1]
- elem.color[2] = mat.diffuse_color[2]
+ elem.color = mat.diffuse_color
else:
elem = tex.color_ramp.elements[0]
- elem.color[0] = mat.diffuse_color[0]
- elem.color[1] = mat.diffuse_color[1]
- elem.color[2] = mat.diffuse_color[2]
+ elem.color = mat.diffuse_color
else:
tex_slot.use_map_color_diffuse = False
@@ -223,14 +235,18 @@ class QuickExplode(bpy.types.Operator):
explode.show_dead = True
else:
settings.factor_random = self.velocity
- settings.angular_velocity_factor = self.velocity/10
+ settings.angular_velocity_factor = self.velocity / 10.0
return {'FINISHED'}
+ def invoke(self, context, event):
+ self.frame_start = context.scene.frame_current
+ self.frame_end = self.frame_start + self.frame_duration
+ return self.execute(context)
def obj_bb_minmax(obj, min_co, max_co):
for i in range(0, 8):
- bb_vec = Vector((obj.bound_box[i][0], obj.bound_box[i][1], obj.bound_box[i][2])) * obj.matrix_world
+ bb_vec = Vector(obj.bound_box[i]) * obj.matrix_world
min_co[0] = min(bb_vec[0], min_co[0])
min_co[1] = min(bb_vec[1], min_co[1])
@@ -260,8 +276,8 @@ class QuickSmoke(bpy.types.Operator):
def execute(self, context):
fake_context = bpy.context.copy()
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
- min_co = Vector((100000, 100000, 100000))
- max_co = Vector((-100000, -100000, -100000))
+ min_co = Vector((100000.0, 100000.0, 100000.0))
+ max_co = -min_co
if not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object.")
@@ -441,4 +457,4 @@ class QuickFluid(bpy.types.Operator):
if self.start_baking:
bpy.ops.fluid.bake()
- return {'FINISHED'} \ No newline at end of file
+ return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 11a129377e8..cb26b093601 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -112,14 +112,25 @@ class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel):
sub.prop(curve, "use_fill_front")
sub.prop(curve, "use_fill_back")
col.prop(curve, "use_fill_deform", text="Fill Deformed")
+
+class DATA_PT_curve_texture_space(CurveButtonsPanel, bpy.types.Panel):
+ bl_label = "Texture Space"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ curve = context.curve
- col.label(text="Textures:")
- col.prop(curve, "use_uv_as_generated")
- col.prop(curve, "use_auto_texspace")
+ row = layout.row()
+ row.prop(curve, "use_auto_texspace")
+ row.prop(curve, "use_uv_as_generated")
row = layout.row()
- row.column().prop(curve, "texspace_location")
- row.column().prop(curve, "texspace_size")
+ row.column().prop(curve, "texspace_location", text="Location")
+ row.column().prop(curve, "texspace_size", text="Size")
class DATA_PT_geometry_curve(CurveButtonsPanel, bpy.types.Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py
index c568d10b3b0..dad308c9058 100644
--- a/release/scripts/startup/bl_ui/properties_data_metaball.py
+++ b/release/scripts/startup/bl_ui/properties_data_metaball.py
@@ -71,9 +71,22 @@ class DATA_PT_metaball(DataButtonsPanel, bpy.types.Panel):
layout.label(text="Update:")
layout.prop(mball, "update_method", expand=True)
+
+class DATA_PT_mball_texture_space(DataButtonsPanel, bpy.types.Panel):
+ bl_label = "Texture Space"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ mball = context.meta_ball
+
+ layout.prop(mball, "use_auto_texspace")
+
row = layout.row()
- row.column().prop(mball, "texspace_location")
- row.column().prop(mball, "texspace_size")
+ row.column().prop(mball, "texspace_location", text="Location")
+ row.column().prop(mball, "texspace_size", text="Size")
class DATA_PT_metaball_element(DataButtonsPanel, bpy.types.Panel):
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 1fb2e5b735e..2b12e75564c 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -350,7 +350,7 @@ class INFO_MT_help(bpy.types.Menu):
layout = self.layout
layout.operator("wm.url_open", text="Manual", icon='HELP').url = 'http://wiki.blender.org/index.php/Doc:Manual'
- layout.operator("wm.url_open", text="Release Log", icon='URL').url = 'http://www.blender.org/development/release-logs/blender-257/'
+ layout.operator("wm.url_open", text="Release Log", icon='URL').url = 'http://www.blender.org/development/release-logs/blender-258/'
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 222f2735a3e..dd5b8438cb2 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -438,6 +438,8 @@ class USERPREF_PT_system(bpy.types.Panel):
col.label(text="OpenGL:")
col.prop(system, "gl_clip_alpha", slider=True)
col.prop(system, "use_mipmaps")
+ col.label(text="Anisotropic Filtering")
+ col.prop(system, "anisotropic_filter", text="")
col.prop(system, "use_vertex_buffer_objects")
#Anti-aliasing is disabled as it breaks broder/lasso select
#col.prop(system, "use_antialiasing")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 6d1caa5111d..44b75f6d75e 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -98,6 +98,8 @@ class VIEW3D_HT_header(bpy.types.Header):
row.prop(toolsettings, "use_snap_peel_object", text="")
elif toolsettings.snap_element == 'FACE':
row.prop(toolsettings, "use_snap_project", text="")
+ if toolsettings.use_snap_project and obj.mode == 'EDIT':
+ row.prop(toolsettings, "use_snap_project_self", text="")
# OpenGL render
row = layout.row(align=True)